WIP: dex redesign
This commit is contained in:
parent
61b3208e0d
commit
04abd67496
42 changed files with 925 additions and 678 deletions
22
src/components/UI/Tabs/index.tsx
Normal file
22
src/components/UI/Tabs/index.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react';
|
||||
import { classes } from '@/utils/utils';
|
||||
import styles from './styles.module.scss';
|
||||
import { TabsProps } from './types';
|
||||
|
||||
const Tabs = ({ data, value, setValue }: TabsProps) => {
|
||||
return (
|
||||
<div className={styles.tabs}>
|
||||
{data.map((tab) => (
|
||||
<button
|
||||
key={tab.type}
|
||||
onClick={() => setValue(tab)}
|
||||
className={classes(styles.tabs__item, value.type === tab.type && styles.active)}
|
||||
>
|
||||
{tab.title} {Number.isFinite(tab.length) && <>({tab.length})</>}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tabs;
|
||||
30
src/components/UI/Tabs/styles.module.scss
Normal file
30
src/components/UI/Tabs/styles.module.scss
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
.tabs {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid var(--delimiter-color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 22px;
|
||||
|
||||
&__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;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
src/components/UI/Tabs/types.ts
Normal file
13
src/components/UI/Tabs/types.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
export type tabsType = {
|
||||
title: string;
|
||||
type: string;
|
||||
length?: number;
|
||||
};
|
||||
|
||||
export interface TabsProps {
|
||||
value: tabsType;
|
||||
setValue: Dispatch<SetStateAction<tabsType>>;
|
||||
data: tabsType[];
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ export default function GenericTable<T>(props: GenericTableProps<T>) {
|
|||
data,
|
||||
getRowKey,
|
||||
emptyMessage = 'No data',
|
||||
getRowProps,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
|
|
@ -65,7 +66,10 @@ export default function GenericTable<T>(props: GenericTableProps<T>) {
|
|||
|
||||
<tbody className={tbodyClassName}>
|
||||
{data.map((row, i) => (
|
||||
<tr key={getRowKey(row, i)}>
|
||||
<tr
|
||||
{...(getRowProps ? getRowProps(row, i) : {})}
|
||||
key={getRowKey(row, i)}
|
||||
>
|
||||
{columns.map((col) => (
|
||||
<td
|
||||
key={col.key}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ export type ColumnDef<T> = {
|
|||
cell: (_row: T, _rowIndex: number) => React.ReactNode;
|
||||
};
|
||||
|
||||
export type RowProps = React.HTMLAttributes<HTMLTableRowElement> & {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export type GenericTableProps<T> = {
|
||||
className?: string;
|
||||
tableClassName?: string;
|
||||
|
|
@ -18,4 +22,5 @@ export type GenericTableProps<T> = {
|
|||
data: T[];
|
||||
getRowKey: (_row: T, _rowIndex: number) => React.Key;
|
||||
emptyMessage?: string;
|
||||
getRowProps?: (_row: T, _index: number) => RowProps | undefined;
|
||||
};
|
||||
|
|
|
|||
96
src/components/dex/AliasCell/index.tsx
Normal file
96
src/components/dex/AliasCell/index.tsx
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import { useEffect, useRef, useState } from 'react';
|
||||
import Tooltip from '@/components/UI/Tooltip/Tooltip';
|
||||
import { cutAddress } from '@/utils/utils';
|
||||
import MatrixConnectionBadge from '@/components/dex/MatrixConnectionBadge';
|
||||
import BadgeStatus from '@/components/dex/BadgeStatus';
|
||||
import { createPortal } from 'react-dom';
|
||||
import styles from './styles.module.scss';
|
||||
import { AliasCellProps } from './types';
|
||||
|
||||
export default function AliasCell({
|
||||
alias,
|
||||
address,
|
||||
matrixAddresses,
|
||||
isInstant,
|
||||
max = 12,
|
||||
}: AliasCellProps) {
|
||||
const display = alias ? cutAddress(alias, max) : 'no alias';
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [pos, setPos] = useState<{ top: number; left: number } | null>(null);
|
||||
const anchorRef = useRef<HTMLParagraphElement | null>(null);
|
||||
|
||||
const updatePosition = () => {
|
||||
const el = anchorRef.current;
|
||||
if (!el) return;
|
||||
const rect = el.getBoundingClientRect();
|
||||
setPos({
|
||||
top: rect.bottom + 8,
|
||||
left: rect.left + rect.width / 2,
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
updatePosition();
|
||||
const onScrollOrResize = () => updatePosition();
|
||||
window.addEventListener('scroll', onScrollOrResize, true);
|
||||
window.addEventListener('resize', onScrollOrResize);
|
||||
return () => {
|
||||
window.removeEventListener('scroll', onScrollOrResize, true);
|
||||
window.removeEventListener('resize', onScrollOrResize);
|
||||
};
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<p ref={anchorRef} className={styles.alias}>
|
||||
<span
|
||||
onMouseEnter={() => {
|
||||
setOpen(true);
|
||||
requestAnimationFrame(updatePosition);
|
||||
}}
|
||||
onMouseLeave={() => setOpen(false)}
|
||||
className={styles.alias__text}
|
||||
>
|
||||
@{display}
|
||||
</span>
|
||||
|
||||
<MatrixConnectionBadge
|
||||
userAdress={address}
|
||||
userAlias={alias}
|
||||
matrixAddresses={matrixAddresses}
|
||||
/>
|
||||
|
||||
{isInstant && (
|
||||
<div style={{ marginLeft: 2 }}>
|
||||
<BadgeStatus type="instant" icon />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{open &&
|
||||
pos &&
|
||||
createPortal(
|
||||
<>
|
||||
{alias && alias.length > max && (
|
||||
<Tooltip
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: pos.top,
|
||||
left: pos.left,
|
||||
transform: 'translateX(-50%)',
|
||||
zIndex: 9999,
|
||||
pointerEvents: 'auto',
|
||||
}}
|
||||
className={styles.tooltip}
|
||||
arrowClass={styles.tooltip__arrow}
|
||||
shown={true}
|
||||
>
|
||||
<p className={styles.tooltip__text}>{alias}</p>
|
||||
</Tooltip>
|
||||
)}
|
||||
</>,
|
||||
document.body,
|
||||
)}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
33
src/components/dex/AliasCell/styles.module.scss
Normal file
33
src/components/dex/AliasCell/styles.module.scss
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
.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 !important;
|
||||
|
||||
&__text {
|
||||
font-size: 12px !important;
|
||||
color: var(--font-main-color) !important;
|
||||
}
|
||||
|
||||
&__arrow {
|
||||
border-radius: 2px;
|
||||
left: 30% !important;
|
||||
background-color: var(--trade-table-tooltip) !important;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,6 @@
|
|||
height: auto;
|
||||
height: 100%;
|
||||
|
||||
height: 515px;
|
||||
|
||||
> canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
|
|||
|
|
@ -1,21 +1,12 @@
|
|||
import LabeledInputProps from '@/interfaces/props/pages/dex/trading/InputPanelItem/LabeledInputProps';
|
||||
import { classes, formatDollarValue } from '@/utils/utils';
|
||||
import { classes } from '@/utils/utils';
|
||||
import { useRef } from 'react';
|
||||
import Input from '@/components/UI/Input/Input';
|
||||
import styles from './styles.module.scss';
|
||||
|
||||
function LabeledInput(props: LabeledInputProps) {
|
||||
const labelRef = useRef<HTMLParagraphElement>(null);
|
||||
const {
|
||||
label = '',
|
||||
placeholder = '',
|
||||
currency = '',
|
||||
value,
|
||||
readonly,
|
||||
usd,
|
||||
setValue,
|
||||
invalid,
|
||||
} = props;
|
||||
const { label = '', currency = '', value, readonly, setValue, invalid } = props;
|
||||
|
||||
const handleInput = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
if (!readonly && setValue) {
|
||||
|
|
@ -29,18 +20,12 @@ function LabeledInput(props: LabeledInputProps) {
|
|||
<div className={classes(styles.labeledInput__wrapper, invalid && styles.invalid)}>
|
||||
<Input
|
||||
bordered
|
||||
placeholder={placeholder}
|
||||
placeholder="0.00"
|
||||
value={value}
|
||||
readOnly={readonly}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
|
||||
{usd && (
|
||||
<div className={styles.labeledInput__value}>
|
||||
<p>~${formatDollarValue(usd)}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={styles.labeledInput__currency} ref={labelRef}>
|
||||
<p>{currency}</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
gap: 8px;
|
||||
|
||||
&__label {
|
||||
font-size: 11px;
|
||||
font-family: 700;
|
||||
font-size: 12px;
|
||||
font-family: 500;
|
||||
line-height: 100%;
|
||||
color: var(--table-th-color);
|
||||
}
|
||||
|
||||
|
|
@ -13,47 +14,43 @@
|
|||
width: 100%;
|
||||
position: relative;
|
||||
background-color: var(--bordered-input-bg);
|
||||
border: 1px solid var(--window-border-color);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--window-border-color);
|
||||
}
|
||||
|
||||
&:focus-within {
|
||||
border-color: #1f8feb;
|
||||
}
|
||||
|
||||
&.invalid {
|
||||
border-color: #ff6767;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 13px 15px;
|
||||
padding: 15px;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
&__value {
|
||||
padding-right: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> p {
|
||||
color: var(--table-th-color);
|
||||
font-size: 12px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
&__currency {
|
||||
min-width: 82px;
|
||||
max-width: 150px;
|
||||
padding: 0 15px;
|
||||
background-color: var(--dex-input-currency);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
> p {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import RangeInput from '@/components/UI/RangeInput/RangeInput';
|
|||
import ConnectButton from '@/components/UI/ConnectButton/ConnectButton';
|
||||
import Button from '@/components/UI/Button/Button';
|
||||
import { useRouter } from 'next/router';
|
||||
import { classes } from '@/utils/utils';
|
||||
import { classes, formatDollarValue } from '@/utils/utils';
|
||||
import InputPanelItemProps from '@/interfaces/props/pages/dex/trading/InputPanelItem/InputPanelItemProps';
|
||||
import CreateOrderData from '@/interfaces/fetch-data/create-order/CreateOrderData';
|
||||
import Decimal from 'decimal.js';
|
||||
|
|
@ -13,6 +13,7 @@ import Alert from '@/components/UI/Alert/Alert';
|
|||
import infoIcon from '@/assets/images/UI/info_alert_icon.svg';
|
||||
import Image from 'next/image';
|
||||
import { useAlert } from '@/hook/useAlert';
|
||||
import { buySellValues } from '@/constants';
|
||||
import styles from './styles.module.scss';
|
||||
import LabeledInput from './components/LabeledInput';
|
||||
|
||||
|
|
@ -21,8 +22,8 @@ function InputPanelItem(props: InputPanelItemProps) {
|
|||
priceState = '',
|
||||
amountState = '',
|
||||
totalState = '',
|
||||
buySellValues,
|
||||
buySellState = buySellValues[0],
|
||||
setBuySellState,
|
||||
setPriceFunction,
|
||||
setAmountFunction,
|
||||
setRangeInputValue,
|
||||
|
|
@ -138,46 +139,83 @@ function InputPanelItem(props: InputPanelItemProps) {
|
|||
)}
|
||||
|
||||
<div className={styles.inputPanel__header}>
|
||||
<h5 className={styles.title}>
|
||||
{isBuy ? 'Buy' : 'Sell'} {secondCurrencyName}
|
||||
</h5>
|
||||
|
||||
<p className={styles.inputPanel__fees}>
|
||||
Fee: <span>0.01 Zano</span>
|
||||
</p>
|
||||
<h5 className={styles.title}>Trade</h5>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputPanel__body}>
|
||||
{LabeledInput({
|
||||
value: priceState,
|
||||
setValue: setPriceFunction,
|
||||
currency: secondCurrencyName,
|
||||
placeholder: '0.00',
|
||||
label: 'Price',
|
||||
invalid: !!priceState && !priceValid,
|
||||
})}
|
||||
<div className={styles.inputPanel__selector}>
|
||||
<button
|
||||
onClick={() => setBuySellState(buySellValues[1])}
|
||||
className={classes(
|
||||
styles.inputPanel__selector_item,
|
||||
buySellState.code === 'buy' && styles.buy,
|
||||
)}
|
||||
>
|
||||
Buy
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setBuySellState(buySellValues[2])}
|
||||
className={classes(
|
||||
styles.inputPanel__selector_item,
|
||||
buySellState.code === 'sell' && styles.sell,
|
||||
)}
|
||||
>
|
||||
Sell
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{LabeledInput({
|
||||
value: amountState,
|
||||
setValue: setAmountFunction,
|
||||
currency: firstCurrencyName,
|
||||
placeholder: '0.00',
|
||||
label: 'Amount',
|
||||
invalid: !!amountState && !amountValid,
|
||||
})}
|
||||
<LabeledInput
|
||||
value={priceState}
|
||||
setValue={setPriceFunction}
|
||||
currency={secondCurrencyName}
|
||||
label="Price"
|
||||
invalid={!!priceState && !priceValid}
|
||||
/>
|
||||
|
||||
<RangeInput value={rangeInputValue} onInput={onRangeInput} />
|
||||
<LabeledInput
|
||||
value={amountState}
|
||||
setValue={setAmountFunction}
|
||||
currency={firstCurrencyName}
|
||||
label="Quantity"
|
||||
invalid={!!amountState && !amountValid}
|
||||
/>
|
||||
|
||||
{LabeledInput({
|
||||
value: totalState,
|
||||
setValue: () => undefined,
|
||||
currency: secondCurrencyName,
|
||||
placeholder: '0.00',
|
||||
label: 'Total',
|
||||
readonly: true,
|
||||
invalid: !!totalState && !totalValid,
|
||||
usd: totalUsd,
|
||||
})}
|
||||
<div>
|
||||
<RangeInput value={rangeInputValue} onInput={onRangeInput} />
|
||||
<div className={styles.inputPanel__body_labels}>
|
||||
<p className={styles.inputPanel__body_labels__item}>0%</p>
|
||||
<p className={styles.inputPanel__body_labels__item}>100%</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputPanel__body_labels}>
|
||||
<p className={styles.inputPanel__body_labels__item}>Available Balance</p>
|
||||
<p className={styles.inputPanel__body_labels__item}>
|
||||
<span>{balance || 0}</span> {firstCurrencyName}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className={styles.inputPanel__body_total}>
|
||||
<LabeledInput
|
||||
value={totalState}
|
||||
setValue={() => undefined}
|
||||
currency={secondCurrencyName}
|
||||
label="Total"
|
||||
readonly={true}
|
||||
invalid={!!totalState && !totalValid}
|
||||
/>
|
||||
|
||||
<div className={styles.inputPanel__body_labels}>
|
||||
<p className={styles.inputPanel__body_labels__item}>
|
||||
Fee: <span>0.01</span> ZANO
|
||||
</p>
|
||||
{totalUsd && (
|
||||
<p className={styles.inputPanel__body_labels__item}>
|
||||
~ ${formatDollarValue(totalUsd)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{state.wallet?.connected ? (
|
||||
<Button
|
||||
disabled={isButtonDisabled}
|
||||
|
|
@ -190,12 +228,7 @@ function InputPanelItem(props: InputPanelItemProps) {
|
|||
{buttonText}
|
||||
</Button>
|
||||
) : (
|
||||
<ConnectButton
|
||||
className={classes(
|
||||
styles.inputPanel__body_btn,
|
||||
isBuy ? styles.buy : styles.sell,
|
||||
)}
|
||||
/>
|
||||
<ConnectButton className={styles.inputPanel__body_btn} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
.inputPanel {
|
||||
width: 100%;
|
||||
max-width: 415px;
|
||||
height: 100%;
|
||||
padding: 15px;
|
||||
background: var(--window-bg-color);
|
||||
border: 1px solid var(--delimiter-color);
|
||||
|
|
@ -9,7 +11,7 @@
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 10px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
margin-bottom: 10px;
|
||||
|
||||
|
|
@ -19,21 +21,65 @@
|
|||
}
|
||||
}
|
||||
|
||||
&__fees {
|
||||
color: var(--table-th-color);
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
&__selector {
|
||||
display: flex;
|
||||
background-color: var(--main-bg-color);
|
||||
padding: 4px;
|
||||
border-radius: 20px;
|
||||
|
||||
span {
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
&_item {
|
||||
cursor: pointer;
|
||||
width: 50%;
|
||||
background-color: transparent;
|
||||
border-radius: 100px;
|
||||
padding-block: 9px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 100%;
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&.buy {
|
||||
background-color: #16d1d6;
|
||||
}
|
||||
|
||||
&.sell {
|
||||
background-color: #ff6767;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
gap: 15px;
|
||||
|
||||
&_labels {
|
||||
margin-top: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
&__item {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 100%;
|
||||
color: var(--table-th-color);
|
||||
|
||||
span {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&_total {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
&_btn {
|
||||
margin-top: 10px;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import Tooltip from '@/components/UI/Tooltip/Tooltip';
|
|||
import { useEffect, useRef, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { ReactComponent as ConnectionIcon } from '@/assets/images/UI/connection.svg';
|
||||
import { classes } from '@/utils/utils';
|
||||
import styles from './styles.module.scss';
|
||||
import { MatrixConnectionBadgeProps } from './types';
|
||||
|
||||
|
|
@ -9,13 +10,14 @@ function MatrixConnectionBadge({
|
|||
userAdress,
|
||||
userAlias,
|
||||
matrixAddresses,
|
||||
className,
|
||||
}: MatrixConnectionBadgeProps) {
|
||||
const hasConnection = (address: string) =>
|
||||
matrixAddresses.some((item) => item.address === address && item.registered);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [pos, setPos] = useState<{ top: number; left: number } | null>(null);
|
||||
const anchorRef = useRef<HTMLAnchorElement | null>(null);
|
||||
const anchorRef = useRef<HTMLParagraphElement | null>(null);
|
||||
|
||||
const updatePosition = () => {
|
||||
const el = anchorRef.current;
|
||||
|
|
@ -42,11 +44,13 @@ function MatrixConnectionBadge({
|
|||
if (!userAdress || !hasConnection(userAdress)) return <></>;
|
||||
|
||||
return (
|
||||
<div className={styles.badge}>
|
||||
<a
|
||||
<div className={classes(styles.badge, className)}>
|
||||
<p
|
||||
ref={anchorRef}
|
||||
href={`https://matrix.to/#/@${userAlias}:zano.org`}
|
||||
target="_blank"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
window.open(`https://matrix.to/#/@${userAlias}:zano.org`);
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
setOpen(true);
|
||||
requestAnimationFrame(updatePosition);
|
||||
|
|
@ -55,7 +59,7 @@ function MatrixConnectionBadge({
|
|||
className={styles.badge__link}
|
||||
>
|
||||
<ConnectionIcon />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
{open &&
|
||||
pos &&
|
||||
|
|
|
|||
|
|
@ -8,13 +8,8 @@
|
|||
|
||||
&__tooltip {
|
||||
padding: 10px;
|
||||
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;
|
||||
|
|
@ -26,4 +21,4 @@
|
|||
background-color: var(--trade-table-tooltip) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import MatrixAddress from '@/interfaces/common/MatrixAddress';
|
||||
|
||||
export interface MatrixConnectionBadgeProps {
|
||||
className?: string;
|
||||
userAdress?: string;
|
||||
userAlias?: string;
|
||||
matrixAddresses: MatrixAddress[];
|
||||
|
|
|
|||
83
src/components/dex/OrdersPool/columns/index.tsx
Normal file
83
src/components/dex/OrdersPool/columns/index.tsx
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import { formatTimestamp, notationToString } from '@/utils/utils';
|
||||
import { ColumnDef } from '@/components/default/GenericTable/types';
|
||||
import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
|
||||
import { Trade } from '@/interfaces/responses/trades/GetTradeRes';
|
||||
import { BuildOrderPoolColumnsArgs, BuildTradesColumnsArgs } from './types';
|
||||
import TotalUsdCell from '../../TotalUsdCell';
|
||||
import AliasCell from '../../AliasCell';
|
||||
|
||||
export function buildOrderPoolColumns({
|
||||
firstCurrencyName,
|
||||
secondCurrencyName,
|
||||
matrixAddresses,
|
||||
}: BuildOrderPoolColumnsArgs): ColumnDef<PageOrderData>[] {
|
||||
return [
|
||||
{
|
||||
key: 'alias',
|
||||
header: 'Alias',
|
||||
width: '100px',
|
||||
className: 'alias',
|
||||
cell: (row) => (
|
||||
<AliasCell
|
||||
alias={row.user?.alias}
|
||||
address={row.user?.address}
|
||||
matrixAddresses={matrixAddresses}
|
||||
isInstant={row.isInstant}
|
||||
max={7}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'price',
|
||||
header: <>Price ({secondCurrencyName})</>,
|
||||
width: '80px',
|
||||
cell: (row) => (
|
||||
<p style={{ color: row.type === 'buy' ? '#16D1D6' : '#FF6767' }}>
|
||||
{notationToString(row.price, 8)}
|
||||
</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'quantity',
|
||||
header: <>Qty ({firstCurrencyName})</>,
|
||||
width: '80px',
|
||||
cell: (row) => <p>{notationToString(row.amount, 8)}</p>,
|
||||
},
|
||||
{
|
||||
key: 'total',
|
||||
header: <>Total ({secondCurrencyName})</>,
|
||||
width: '80px',
|
||||
cell: (row) => <TotalUsdCell amount={row.left} price={row.price} fixed={4} />,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function buildTradesColumns({
|
||||
firstCurrencyName,
|
||||
secondCurrencyName,
|
||||
}: BuildTradesColumnsArgs): ColumnDef<Trade>[] {
|
||||
return [
|
||||
{
|
||||
key: 'price',
|
||||
header: <>Price ({secondCurrencyName})</>,
|
||||
width: '80px',
|
||||
cell: (row) => (
|
||||
<p style={{ color: row.type === 'buy' ? '#16D1D6' : '#FF6767' }}>
|
||||
{notationToString(row.price)}
|
||||
</p>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'quantity',
|
||||
header: <>Qty ({firstCurrencyName})</>,
|
||||
width: '80px',
|
||||
cell: (row) => <p>{notationToString(row.amount)}</p>,
|
||||
},
|
||||
{
|
||||
key: 'time',
|
||||
header: <>Time</>,
|
||||
width: '80px',
|
||||
cell: (row) => <p>{formatTimestamp(row.timestamp)}</p>,
|
||||
},
|
||||
];
|
||||
}
|
||||
12
src/components/dex/OrdersPool/columns/types.ts
Normal file
12
src/components/dex/OrdersPool/columns/types.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import MatrixAddress from '@/interfaces/common/MatrixAddress';
|
||||
|
||||
export interface BuildOrderPoolColumnsArgs {
|
||||
firstCurrencyName: string;
|
||||
secondCurrencyName: string;
|
||||
matrixAddresses: MatrixAddress[];
|
||||
}
|
||||
|
||||
export interface BuildTradesColumnsArgs {
|
||||
firstCurrencyName: string;
|
||||
secondCurrencyName: string;
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
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 (
|
||||
<tr
|
||||
onMouseEnter={() => 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)}
|
||||
>
|
||||
<OrderRowTooltipCell
|
||||
style={{
|
||||
color: e.type === 'buy' ? '#16D1D6' : '#FF6767',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '8px',
|
||||
maxWidth: 'max-content',
|
||||
}}
|
||||
>
|
||||
{notationToString(e.price)}
|
||||
</OrderRowTooltipCell>
|
||||
<OrderRowTooltipCell>{notationToString(e.amount)}</OrderRowTooltipCell>
|
||||
<OrderRowTooltipCell
|
||||
noTooltip
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '8px',
|
||||
maxWidth: 'max-content',
|
||||
}}
|
||||
>
|
||||
{notationToString(totalDecimal.toString())}
|
||||
</OrderRowTooltipCell>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default OrdersRow;
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
export interface OrdersRowProps {
|
||||
orderData: PageOrderData;
|
||||
percentage: number;
|
||||
takeOrderClick: (
|
||||
_event:
|
||||
| React.MouseEvent<HTMLAnchorElement, MouseEvent>
|
||||
| React.MouseEvent<HTMLTableRowElement, MouseEvent>,
|
||||
_e: PageOrderData,
|
||||
) => void;
|
||||
setOrdersInfoTooltip: Dispatch<SetStateAction<PageOrderData | null>>;
|
||||
}
|
||||
|
|
@ -1,17 +1,30 @@
|
|||
import React, { useRef, useState } from 'react';
|
||||
import React, { useMemo, 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 { tabsType } from '@/components/UI/Tabs/types';
|
||||
import Tabs from '@/components/UI/Tabs';
|
||||
import GenericTable from '@/components/default/GenericTable';
|
||||
import styles from './styles.module.scss';
|
||||
import BadgeStatus from '../BadgeStatus';
|
||||
import { OrdersPoolProps } from './types';
|
||||
import { buildOrderPoolColumns, buildTradesColumns } from './columns';
|
||||
|
||||
const tabsData: tabsType[] = [
|
||||
{
|
||||
title: 'Order Pool',
|
||||
type: 'orders',
|
||||
},
|
||||
{
|
||||
title: 'Recent Trades',
|
||||
type: 'trades',
|
||||
},
|
||||
];
|
||||
|
||||
const OrdersPool = (props: OrdersPoolProps) => {
|
||||
const {
|
||||
|
|
@ -22,103 +35,197 @@ const OrdersPool = (props: OrdersPoolProps) => {
|
|||
filteredOrdersHistory,
|
||||
secondAssetUsdPrice,
|
||||
takeOrderClick,
|
||||
matrixAddresses,
|
||||
trades,
|
||||
tradesLoading,
|
||||
} = props;
|
||||
const ordersInfoRef = useRef<HTMLTableSectionElement | null>(null);
|
||||
const { firstCurrencyName, secondCurrencyName } = currencyNames;
|
||||
const [infoTooltipPos, setInfoTooltipPos] = useState({ x: 0, y: 0 });
|
||||
const [ordersInfoTooltip, setOrdersInfoTooltip] = useState<PageOrderData | null>(null);
|
||||
const [currentOrder, setCurrentOrder] = useState<tabsType>(tabsData[0]);
|
||||
const { maxBuyLeftValue, maxSellLeftValue } = filteredOrdersHistory.reduce(
|
||||
(acc, order) => {
|
||||
const left = parseFloat(String(order.left)) || 0;
|
||||
if (order.type === 'buy') acc.maxBuyLeftValue = Math.max(acc.maxBuyLeftValue, left);
|
||||
if (order.type === 'sell') acc.maxSellLeftValue = Math.max(acc.maxSellLeftValue, left);
|
||||
return acc;
|
||||
},
|
||||
{ maxBuyLeftValue: 0, maxSellLeftValue: 0 },
|
||||
);
|
||||
|
||||
const totalLeft = maxBuyLeftValue + maxSellLeftValue;
|
||||
|
||||
const moveInfoTooltip = (event: React.MouseEvent) => {
|
||||
setInfoTooltipPos({ x: event.clientX, y: event.clientY });
|
||||
};
|
||||
|
||||
const ordersPool = useMemo(
|
||||
() =>
|
||||
buildOrderPoolColumns({
|
||||
firstCurrencyName,
|
||||
secondCurrencyName,
|
||||
matrixAddresses,
|
||||
}),
|
||||
[firstCurrencyName, secondCurrencyName, matrixAddresses],
|
||||
);
|
||||
|
||||
const tradeOrders = useMemo(
|
||||
() =>
|
||||
buildTradesColumns({
|
||||
firstCurrencyName,
|
||||
secondCurrencyName,
|
||||
}),
|
||||
[firstCurrencyName, secondCurrencyName],
|
||||
);
|
||||
|
||||
const renderTable = () => {
|
||||
switch (currentOrder.type) {
|
||||
case 'orders':
|
||||
return (
|
||||
<>
|
||||
{!ordersLoading ? (
|
||||
<div onMouseMove={moveInfoTooltip} ref={ordersInfoRef}>
|
||||
<GenericTable
|
||||
className={styles.ordersPool__content_orders}
|
||||
tableClassName={styles.table}
|
||||
tbodyClassName={styles.table__body}
|
||||
theadClassName={styles.table__header}
|
||||
columns={ordersPool}
|
||||
data={filteredOrdersHistory.sort((a, b) => {
|
||||
if (a.type === b.type) return 0;
|
||||
return a.type === 'buy' ? -1 : 1;
|
||||
})}
|
||||
getRowKey={(r) => r.id}
|
||||
getRowProps={(row) => ({
|
||||
className: styles[row.type],
|
||||
style: {
|
||||
'--precentage': `${(
|
||||
(parseFloat(String(row.left)) /
|
||||
(row.type === 'buy'
|
||||
? maxBuyLeftValue
|
||||
: maxSellLeftValue)) *
|
||||
100
|
||||
).toFixed(2)}%`,
|
||||
} as React.CSSProperties,
|
||||
onClick: (event) => {
|
||||
takeOrderClick(event, row);
|
||||
},
|
||||
onMouseMove: (event) => {
|
||||
const tr = event.target as HTMLElement;
|
||||
if (tr.classList.contains('alias')) {
|
||||
setOrdersInfoTooltip(null);
|
||||
}
|
||||
},
|
||||
onMouseEnter: () => {
|
||||
setOrdersInfoTooltip(row);
|
||||
},
|
||||
onMouseLeave: () => {
|
||||
setOrdersInfoTooltip(null);
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<ContentPreloader style={{ marginTop: 40 }} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
case 'trades':
|
||||
return (
|
||||
<>
|
||||
{!tradesLoading ? (
|
||||
<GenericTable
|
||||
className={styles.ordersPool__content_orders}
|
||||
tableClassName={styles.table}
|
||||
tbodyClassName={styles.table__body}
|
||||
theadClassName={styles.table__header}
|
||||
columns={tradeOrders}
|
||||
data={trades}
|
||||
getRowKey={(r) => r.id}
|
||||
/>
|
||||
) : (
|
||||
<ContentPreloader style={{ marginTop: 40 }} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
useMouseLeave(ordersInfoRef, () => setOrdersInfoTooltip(null));
|
||||
return (
|
||||
<>
|
||||
<div className={styles.ordersPool}>
|
||||
<div className={styles.ordersPool__header}>
|
||||
<h5 className={styles.ordersPool__header_title}>Orders pool</h5>
|
||||
<Tabs value={currentOrder} setValue={setCurrentOrder} data={tabsData} />
|
||||
|
||||
<div className={styles.ordersPool__header_type}>
|
||||
<button
|
||||
onClick={() => setOrdersBuySell(buySellValues[0])}
|
||||
className={classes(
|
||||
styles.btn,
|
||||
styles.all,
|
||||
ordersBuySell.code === 'all' && styles.selected,
|
||||
)}
|
||||
></button>
|
||||
{currentOrder.type === 'orders' && (
|
||||
<div className={styles.ordersPool__header_type}>
|
||||
<button
|
||||
onClick={() => setOrdersBuySell(buySellValues[0])}
|
||||
className={classes(
|
||||
styles.btn,
|
||||
styles.all,
|
||||
ordersBuySell.code === 'all' && styles.selected,
|
||||
)}
|
||||
></button>
|
||||
|
||||
<button
|
||||
onClick={() => setOrdersBuySell(buySellValues[1])}
|
||||
className={classes(
|
||||
styles.btn,
|
||||
styles.buy,
|
||||
ordersBuySell.code === 'buy' && styles.selected,
|
||||
)}
|
||||
>
|
||||
B
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setOrdersBuySell(buySellValues[1])}
|
||||
className={classes(
|
||||
styles.btn,
|
||||
styles.buy,
|
||||
ordersBuySell.code === 'buy' && styles.selected,
|
||||
)}
|
||||
>
|
||||
B
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setOrdersBuySell(buySellValues[2])}
|
||||
className={classes(
|
||||
styles.btn,
|
||||
styles.sell,
|
||||
ordersBuySell.code === 'sell' && styles.selected,
|
||||
)}
|
||||
>
|
||||
S
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setOrdersBuySell(buySellValues[2])}
|
||||
className={classes(
|
||||
styles.btn,
|
||||
styles.sell,
|
||||
ordersBuySell.code === 'sell' && styles.selected,
|
||||
)}
|
||||
>
|
||||
S
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.ordersPool__content}>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Price ({secondCurrencyName})</th>
|
||||
<th>Amount ({firstCurrencyName})</th>
|
||||
<th>Total ({secondCurrencyName})</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{renderTable()}
|
||||
|
||||
{!ordersLoading && !!filteredOrdersHistory.length && (
|
||||
<tbody
|
||||
ref={ordersInfoRef}
|
||||
onMouseMove={moveInfoTooltip}
|
||||
onMouseLeave={() => setOrdersInfoTooltip(null)}
|
||||
className="orders-scroll"
|
||||
{currentOrder.type === 'orders' && (
|
||||
<div className={styles.ordersPool__content_stats}>
|
||||
<div
|
||||
style={
|
||||
{
|
||||
'--width': `${(maxBuyLeftValue / totalLeft) * 100}%`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
className={classes(styles.stat_item, styles.buy)}
|
||||
>
|
||||
{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 (
|
||||
<OrdersRow
|
||||
orderData={e}
|
||||
percentage={Number(percentage)}
|
||||
key={nanoid(16)}
|
||||
takeOrderClick={takeOrderClick}
|
||||
setOrdersInfoTooltip={setOrdersInfoTooltip}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
)}
|
||||
</table>
|
||||
|
||||
{!filteredOrdersHistory.length && !ordersLoading && (
|
||||
<EmptyMessage text="No orders" />
|
||||
<div className={styles.stat_item__badge}>B</div>{' '}
|
||||
{notationToString((maxBuyLeftValue / totalLeft) * 100, 0)}%
|
||||
</div>
|
||||
<div
|
||||
style={
|
||||
{
|
||||
'--width': `${(maxSellLeftValue / totalLeft) * 100}%`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
className={classes(styles.stat_item, styles.sell)}
|
||||
>
|
||||
{notationToString((maxSellLeftValue / totalLeft) * 100, 0)}%{' '}
|
||||
<div className={styles.stat_item__badge}>S</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{ordersLoading && <ContentPreloader style={{ marginTop: 40 }} />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,18 @@
|
|||
.ordersPool {
|
||||
position: relative;
|
||||
max-width: 415px;
|
||||
width: 100%;
|
||||
height: 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;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid var(--delimiter-color);
|
||||
|
||||
&_title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&_type {
|
||||
display: flex;
|
||||
|
|
@ -38,10 +28,11 @@
|
|||
font-weight: 700;
|
||||
transition: 0.3s opacity ease;
|
||||
color: #ffffff;
|
||||
opacity: 60%;
|
||||
|
||||
&.selected,
|
||||
&:hover {
|
||||
opacity: 80%;
|
||||
opacity: 100%;
|
||||
}
|
||||
|
||||
&.all {
|
||||
|
|
@ -63,44 +54,138 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 10px;
|
||||
width: 100%;
|
||||
|
||||
table {
|
||||
&_orders {
|
||||
width: 100%;
|
||||
height: 410px;
|
||||
|
||||
thead {
|
||||
display: flex;
|
||||
.table {
|
||||
width: 100%;
|
||||
padding-inline: 10px;
|
||||
margin-bottom: 9px;
|
||||
|
||||
tr {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
&__header {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
|
||||
th {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
text-align: start;
|
||||
color: var(--table-th-color);
|
||||
min-width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
text-align: right;
|
||||
&__body {
|
||||
tr {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--table-tr-hover-color);
|
||||
}
|
||||
|
||||
&.buy {
|
||||
td {
|
||||
&:last-child {
|
||||
&::before {
|
||||
background-color: var(--dex-buy-percentage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.sell {
|
||||
td {
|
||||
&:last-child {
|
||||
&::before {
|
||||
background-color: var(--dex-sell-percentage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
position: static !important;
|
||||
|
||||
|
||||
|
||||
&:last-child {
|
||||
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: var(--precentage);
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
p,
|
||||
span {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
height: 29dvh;
|
||||
min-height: 265px;
|
||||
max-height: 380px;
|
||||
&_stats {
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: calc(100% - 30px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1px;
|
||||
|
||||
.stat_item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
padding-bottom: 20px;
|
||||
padding: 10px;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 100%;
|
||||
font-weight: 400;
|
||||
min-width: 60px;
|
||||
|
||||
&.buy {
|
||||
width: var(--width);
|
||||
background-color: var(--dex-buy-percentage);
|
||||
color: #16d1d6;
|
||||
|
||||
.stat_item__badge {
|
||||
background-color: #16d1d6;
|
||||
}
|
||||
}
|
||||
|
||||
&.sell {
|
||||
width: var(--width);
|
||||
background-color: var(--dex-sell-percentage);
|
||||
justify-content: flex-end;
|
||||
color: #ff6767;
|
||||
|
||||
.stat_item__badge {
|
||||
background-color: #ff6767;
|
||||
}
|
||||
}
|
||||
|
||||
&__badge {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 4px;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 120%;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -148,4 +233,4 @@
|
|||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
import { Dispatch, SetStateAction } from 'react';
|
||||
import SelectValue from '@/interfaces/states/pages/dex/trading/InputPanelItem/SelectValue';
|
||||
import { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
|
||||
import MatrixAddress from '@/interfaces/common/MatrixAddress';
|
||||
import { Trade } from '@/interfaces/responses/trades/GetTradeRes';
|
||||
|
||||
export interface OrdersPoolProps {
|
||||
ordersBuySell: SelectValue;
|
||||
secondAssetUsdPrice: number | undefined;
|
||||
setOrdersBuySell: Dispatch<SetStateAction<SelectValue>>;
|
||||
currencyNames: {
|
||||
firstCurrencyName: string;
|
||||
|
|
@ -11,11 +14,11 @@ export interface OrdersPoolProps {
|
|||
};
|
||||
ordersLoading: boolean;
|
||||
filteredOrdersHistory: PageOrderData[];
|
||||
secondAssetUsdPrice: number | undefined;
|
||||
trades: Trade[];
|
||||
tradesLoading: boolean;
|
||||
matrixAddresses: MatrixAddress[];
|
||||
takeOrderClick: (
|
||||
_event:
|
||||
| React.MouseEvent<HTMLAnchorElement, MouseEvent>
|
||||
| React.MouseEvent<HTMLTableRowElement, MouseEvent>,
|
||||
_event: React.MouseEvent<HTMLTableRowElement, MouseEvent>,
|
||||
_e: PageOrderData,
|
||||
) => void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@ import Decimal from 'decimal.js';
|
|||
import { notationToString, formatDollarValue } from '@/utils/utils';
|
||||
import { TotalUsdCellProps } from './types';
|
||||
|
||||
export default function TotalUsdCell({ amount, price, secondAssetUsdPrice }: TotalUsdCellProps) {
|
||||
export default function TotalUsdCell({
|
||||
amount,
|
||||
price,
|
||||
secondAssetUsdPrice,
|
||||
fixed,
|
||||
}: TotalUsdCellProps) {
|
||||
const total = useMemo(
|
||||
() => new Decimal(amount || 0).mul(new Decimal(price || 0)),
|
||||
[amount, price],
|
||||
|
|
@ -12,7 +17,8 @@ export default function TotalUsdCell({ amount, price, secondAssetUsdPrice }: Tot
|
|||
|
||||
return (
|
||||
<p>
|
||||
{notationToString(total.toString())} <span>~ ${usd && formatDollarValue(usd)}</span>
|
||||
{notationToString((fixed ? total.toFixed(fixed) : total).toString())}{' '}
|
||||
{secondAssetUsdPrice && <span>~ ${usd && formatDollarValue(usd)}</span>}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
|
@ -2,4 +2,5 @@ export interface TotalUsdCellProps {
|
|||
amount: string | number;
|
||||
price: string | number;
|
||||
secondAssetUsdPrice?: number;
|
||||
fixed?: number;
|
||||
}
|
||||
|
|
@ -5,8 +5,8 @@ import ApplyTip from '@/interfaces/common/ApplyTip';
|
|||
import UserPendingType from '@/interfaces/common/UserPendingType';
|
||||
import { UserOrderData } from '@/interfaces/responses/orders/GetUserOrdersRes';
|
||||
import CancelActionCell from '../components/CancelActionCell';
|
||||
import AliasCell from '../components/AliasCell';
|
||||
import TotalUsdCell from '../components/TotalUsdCell';
|
||||
import AliasCell from '../../AliasCell';
|
||||
import TotalUsdCell from '../../TotalUsdCell';
|
||||
import RequestActionCell from '../components/RequestActionCell';
|
||||
import {
|
||||
BuildApplyTipsColumnsArgs,
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
import { useState } from 'react';
|
||||
import Tooltip from '@/components/UI/Tooltip/Tooltip';
|
||||
import { cutAddress } from '@/utils/utils';
|
||||
import MatrixConnectionBadge from '@/components/dex/MatrixConnectionBadge';
|
||||
import BadgeStatus from '@/components/dex/BadgeStatus';
|
||||
import styles from '../../styles.module.scss';
|
||||
import { AliasCellProps } from './types';
|
||||
|
||||
export default function AliasCell({
|
||||
alias,
|
||||
address,
|
||||
matrixAddresses,
|
||||
isInstant,
|
||||
max = 12,
|
||||
}: AliasCellProps) {
|
||||
const [show, setShow] = useState(false);
|
||||
const display = alias ? cutAddress(alias, max) : 'no alias';
|
||||
|
||||
return (
|
||||
<p className={styles.alias}>
|
||||
<span
|
||||
onMouseEnter={() => setShow(true)}
|
||||
onMouseLeave={() => setShow(false)}
|
||||
className={styles.alias__text}
|
||||
>
|
||||
@{display}
|
||||
</span>
|
||||
|
||||
<MatrixConnectionBadge
|
||||
userAdress={address}
|
||||
userAlias={alias}
|
||||
matrixAddresses={matrixAddresses}
|
||||
/>
|
||||
{isInstant && (
|
||||
<div style={{ marginLeft: 2 }}>
|
||||
<BadgeStatus type="instant" icon />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{alias && alias.length > max && (
|
||||
<Tooltip className={styles.tooltip} arrowClass={styles.tooltip__arrow} shown={show}>
|
||||
<p className={styles.tooltip__text}>{alias}</p>
|
||||
</Tooltip>
|
||||
)}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ import { classes } from '@/utils/utils';
|
|||
import ContentPreloader from '@/components/UI/ContentPreloader/ContentPreloader';
|
||||
import useUpdateUser from '@/hook/useUpdateUser';
|
||||
import EmptyMessage from '@/components/UI/EmptyMessage';
|
||||
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { useContext, useEffect, useMemo, useState } from 'react';
|
||||
import GenericTable from '@/components/default/GenericTable';
|
||||
import ActionBtn from '@/components/UI/ActionBtn';
|
||||
import { getUserOrders, getUserPendings } from '@/utils/methods';
|
||||
|
|
@ -11,7 +11,9 @@ import { Store } from '@/store/store-reducer';
|
|||
import { UserOrderData } from '@/interfaces/responses/orders/GetUserOrdersRes';
|
||||
import { useAlert } from '@/hook/useAlert';
|
||||
import Alert from '@/components/UI/Alert/Alert';
|
||||
import { tabsType, UserOrdersProps } from './types';
|
||||
import { tabsType } from '@/components/UI/Tabs/types';
|
||||
import Tabs from '@/components/UI/Tabs';
|
||||
import { UserOrdersProps } from './types';
|
||||
import styles from './styles.module.scss';
|
||||
import {
|
||||
buildApplyTipsColumns,
|
||||
|
|
@ -24,8 +26,6 @@ const UserOrders = ({
|
|||
userOrders,
|
||||
applyTips,
|
||||
myOrdersLoading,
|
||||
ordersType,
|
||||
setOrdersType,
|
||||
handleCancelAllOrders,
|
||||
orderListRef,
|
||||
matrixAddresses,
|
||||
|
|
@ -43,6 +43,45 @@ const UserOrders = ({
|
|||
const [userRequests, setUserRequests] = useState<UserPendingType[]>([]);
|
||||
const [ordersHistory, setOrdersHistory] = useState<UserOrderData[]>([]);
|
||||
|
||||
const tabsData: tabsType[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: 'Open Orders',
|
||||
type: 'opened',
|
||||
length: userOrders.length,
|
||||
},
|
||||
{
|
||||
title: 'Suitable',
|
||||
type: 'suitable',
|
||||
length: suitables.length,
|
||||
},
|
||||
{
|
||||
title: 'My requests',
|
||||
type: 'requests',
|
||||
length: userRequests.length,
|
||||
},
|
||||
{
|
||||
title: 'Offers',
|
||||
type: 'offers',
|
||||
length: offers.length,
|
||||
},
|
||||
{
|
||||
title: 'Order history',
|
||||
type: 'history',
|
||||
length: ordersHistory.length,
|
||||
},
|
||||
],
|
||||
[
|
||||
offers.length,
|
||||
userOrders.length,
|
||||
suitables.length,
|
||||
userRequests.length,
|
||||
ordersHistory.length,
|
||||
],
|
||||
);
|
||||
|
||||
const [ordersType, setOrdersType] = useState<tabsType>(tabsData[0]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const requestsData = await getUserPendings();
|
||||
|
|
@ -166,7 +205,7 @@ const UserOrders = ({
|
|||
);
|
||||
|
||||
const renderTable = () => {
|
||||
switch (ordersType) {
|
||||
switch (ordersType.type) {
|
||||
case 'opened':
|
||||
return (
|
||||
<GenericTable
|
||||
|
|
@ -222,53 +261,13 @@ const UserOrders = ({
|
|||
}
|
||||
};
|
||||
|
||||
const tabsData: tabsType[] = [
|
||||
{
|
||||
title: 'Open Orders',
|
||||
type: 'opened',
|
||||
length: userOrders.length,
|
||||
},
|
||||
{
|
||||
title: 'Suitable',
|
||||
type: 'suitable',
|
||||
length: suitables.length,
|
||||
},
|
||||
{
|
||||
title: 'My requests',
|
||||
type: 'requests',
|
||||
length: userRequests.length,
|
||||
},
|
||||
{
|
||||
title: 'Offers',
|
||||
type: 'offers',
|
||||
length: offers.length,
|
||||
},
|
||||
{
|
||||
title: 'Order history',
|
||||
type: 'history',
|
||||
length: ordersHistory.length,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<>
|
||||
<div ref={orderListRef} className={styles.userOrders}>
|
||||
<div className={styles.userOrders__header}>
|
||||
<div className={styles.userOrders__header_nav}>
|
||||
{tabsData.map((tab) => (
|
||||
<button
|
||||
key={tab.type}
|
||||
onClick={() => setOrdersType(tab.type)}
|
||||
className={classes(
|
||||
styles.navItem,
|
||||
ordersType === tab.type && styles.active,
|
||||
)}
|
||||
>
|
||||
{tab.title} ({tab.length})
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<Tabs data={tabsData} value={ordersType} setValue={setOrdersType} />
|
||||
|
||||
{ordersType === 'opened' && userOrders.length > 0 && (
|
||||
{ordersType?.type === 'opened' && userOrders.length > 0 && (
|
||||
<ActionBtn
|
||||
className={styles.userOrders__header_btn}
|
||||
onClick={handleCancelAllOrders}
|
||||
|
|
|
|||
|
|
@ -1,62 +1,29 @@
|
|||
.userOrders {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
background: var(--window-bg-color);
|
||||
border: 1px solid var(--delimiter-color);
|
||||
border-radius: 10px;
|
||||
padding: 1px;
|
||||
min-height: 310px;
|
||||
|
||||
&__body {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 20px;
|
||||
height: 260px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
padding-top: 10px;
|
||||
padding-top: 14px;
|
||||
margin-inline: 14px;
|
||||
padding-bottom: 0;
|
||||
border-bottom: 1px solid var(--delimiter-color);
|
||||
|
||||
&_nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 22px;
|
||||
|
||||
.navItem {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&_btn {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
right: 0px;
|
||||
top: 7px;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
|
@ -90,7 +57,7 @@
|
|||
td {
|
||||
position: relative;
|
||||
|
||||
> p {
|
||||
>p {
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
|
|
@ -109,7 +76,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
> span {
|
||||
>span {
|
||||
line-height: 1;
|
||||
color: var(--font-dimmed-color);
|
||||
font-size: 11px;
|
||||
|
|
@ -118,37 +85,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,24 +2,14 @@ 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 { PageOrderData } from '@/interfaces/responses/orders/GetOrdersPageRes';
|
||||
import { Dispatch, ForwardedRef, SetStateAction } from 'react';
|
||||
import { ForwardedRef } from 'react';
|
||||
|
||||
export type OrderType = 'opened' | 'suitable' | 'requests' | 'offers' | 'history';
|
||||
|
||||
export type tabsType = {
|
||||
title: string;
|
||||
type: OrderType;
|
||||
length: number;
|
||||
};
|
||||
|
||||
export interface UserOrdersProps {
|
||||
orderListRef: ForwardedRef<HTMLDivElement>;
|
||||
userOrders: OrderRow[];
|
||||
applyTips: ApplyTip[];
|
||||
myOrdersLoading: boolean;
|
||||
ordersType: OrderType;
|
||||
setOrdersType: Dispatch<SetStateAction<OrderType>>;
|
||||
handleCancelAllOrders: () => void;
|
||||
secondAssetUsdPrice: number | undefined;
|
||||
matrixAddresses: MatrixAddress[];
|
||||
|
|
|
|||
|
|
@ -1,33 +1,16 @@
|
|||
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 useFilteredData = ({ ordersHistory, ordersBuySell }: 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)
|
||||
|
|
@ -40,7 +23,6 @@ const useFilteredData = ({
|
|||
|
||||
return {
|
||||
filteredOrdersHistory,
|
||||
filteredTrades,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,12 @@ import OrderFormOutput from '@/interfaces/common/orderFormOutput';
|
|||
import { handleInputChange } from '@/utils/handleInputChange';
|
||||
|
||||
interface UseOrderFormParams {
|
||||
type: 'buy' | 'sell';
|
||||
pairData: PairData | null;
|
||||
balance: string | undefined;
|
||||
assetsRates: Map<string, number>;
|
||||
}
|
||||
|
||||
export function useOrderForm({
|
||||
type,
|
||||
pairData,
|
||||
balance,
|
||||
assetsRates,
|
||||
|
|
|
|||
|
|
@ -37,15 +37,7 @@ const useTradeInit = ({ pairData, pairStats }: useTradeInitParams) => {
|
|||
? new Decimal(pairStats.rate).mul(secondAssetUsdPrice).toFixed(2)
|
||||
: undefined;
|
||||
|
||||
const buyForm = useOrderForm({
|
||||
type: 'buy',
|
||||
pairData,
|
||||
balance,
|
||||
assetsRates: state.assetsRates,
|
||||
});
|
||||
|
||||
const sellForm = useOrderForm({
|
||||
type: 'sell',
|
||||
const orderForm = useOrderForm({
|
||||
pairData,
|
||||
balance,
|
||||
assetsRates: state.assetsRates,
|
||||
|
|
@ -57,8 +49,7 @@ const useTradeInit = ({ pairData, pairStats }: useTradeInitParams) => {
|
|||
secondAssetLink,
|
||||
secondAssetUsdPrice,
|
||||
balance,
|
||||
buyForm,
|
||||
sellForm,
|
||||
orderForm,
|
||||
pairRateUsd,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ interface InputPanelItemProps {
|
|||
priceState: string;
|
||||
amountState: string;
|
||||
totalState: string;
|
||||
buySellValues: SelectValue[];
|
||||
buySellState: SelectValue;
|
||||
setBuySellState: Dispatch<SetStateAction<SelectValue>>;
|
||||
setPriceFunction: (_value: string) => void;
|
||||
setAmountFunction: (_value: string) => void;
|
||||
setRangeInputValue: Dispatch<SetStateAction<string>>;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ interface LabeledInputProps {
|
|||
label: string;
|
||||
value: string;
|
||||
setValue: (_value: string) => void;
|
||||
placeholder: string;
|
||||
currency: string;
|
||||
usd?: string;
|
||||
readonly?: boolean;
|
||||
invalid?: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import useFilteredData from '@/hook/useFilteredData';
|
|||
import useTradeInit from '@/hook/useTradeInit';
|
||||
import useMatrixAddresses from '@/hook/useMatrixAddresses';
|
||||
import takeOrderClick from '@/utils/takeOrderClick';
|
||||
import { OrderType } from '@/components/dex/UserOrders/types';
|
||||
import useUpdateUser from '@/hook/useUpdateUser';
|
||||
|
||||
const CHART_OPTIONS = [{ name: 'Zano Chart' }, { name: 'Trading View', disabled: true }];
|
||||
|
|
@ -52,15 +51,13 @@ function Trading() {
|
|||
const [trades, setTrades] = useState<Trade[]>([]);
|
||||
const [myOrdersLoading, setMyOrdersLoading] = useState(true);
|
||||
const [ordersBuySell, setOrdersBuySell] = useState(buySellValues[0]);
|
||||
const [tradesType, setTradesType] = useState<'all' | 'my'>('all');
|
||||
const [ordersType, setOrdersType] = useState<OrderType>('opened');
|
||||
const [pairStats, setPairStats] = useState<PairStats | null>(null);
|
||||
const [applyTips, setApplyTips] = useState<ApplyTip[]>([]);
|
||||
const matrixAddresses = useMatrixAddresses(ordersHistory);
|
||||
const [orderFormType, setOrderFormType] = useState(buySellValues[1]);
|
||||
|
||||
const {
|
||||
buyForm,
|
||||
sellForm,
|
||||
orderForm,
|
||||
currencyNames,
|
||||
firstAssetLink,
|
||||
secondAssetLink,
|
||||
|
|
@ -99,23 +96,21 @@ function Trading() {
|
|||
|
||||
// Take order from trades
|
||||
const onHandleTakeOrder = useCallback(
|
||||
(
|
||||
event:
|
||||
| React.MouseEvent<HTMLAnchorElement, MouseEvent>
|
||||
| React.MouseEvent<HTMLTableRowElement, MouseEvent>,
|
||||
e: PageOrderData,
|
||||
) => {
|
||||
(event: React.MouseEvent<HTMLTableRowElement, MouseEvent>, e: PageOrderData) => {
|
||||
setOrderFormType(() => {
|
||||
return e.type === 'buy' ? buySellValues[2] : buySellValues[1];
|
||||
});
|
||||
|
||||
takeOrderClick({
|
||||
event,
|
||||
PageOrderData: e,
|
||||
balance,
|
||||
buyForm,
|
||||
orderForm,
|
||||
pairData,
|
||||
scrollToOrderForm,
|
||||
sellForm,
|
||||
});
|
||||
},
|
||||
[balance, buyForm, pairData, scrollToOrderForm, sellForm],
|
||||
[balance, orderForm, pairData, scrollToOrderForm],
|
||||
);
|
||||
|
||||
// Cancel all user orders
|
||||
|
|
@ -134,11 +129,9 @@ function Trading() {
|
|||
}
|
||||
}, [userOrders, updateUserOrders]);
|
||||
|
||||
const { filteredOrdersHistory, filteredTrades } = useFilteredData({
|
||||
const { filteredOrdersHistory } = useFilteredData({
|
||||
ordersBuySell,
|
||||
ordersHistory,
|
||||
trades,
|
||||
tradesType,
|
||||
});
|
||||
|
||||
const onAfter = async () => {
|
||||
|
|
@ -166,12 +159,15 @@ function Trading() {
|
|||
<div className={styles.trading__top}>
|
||||
<OrdersPool
|
||||
currencyNames={currencyNames}
|
||||
filteredOrdersHistory={filteredOrdersHistory}
|
||||
secondAssetUsdPrice={secondAssetUsdPrice}
|
||||
ordersBuySell={ordersBuySell}
|
||||
ordersLoading={ordersLoading}
|
||||
secondAssetUsdPrice={secondAssetUsdPrice}
|
||||
filteredOrdersHistory={filteredOrdersHistory}
|
||||
trades={trades}
|
||||
tradesLoading={tradesLoading}
|
||||
setOrdersBuySell={setOrdersBuySell}
|
||||
takeOrderClick={onHandleTakeOrder}
|
||||
matrixAddresses={matrixAddresses}
|
||||
/>
|
||||
|
||||
<div className={styles.trading__top_chart}>
|
||||
|
|
@ -198,13 +194,34 @@ function Trading() {
|
|||
)}
|
||||
</div>
|
||||
|
||||
<AllTrades
|
||||
<div ref={orderFormRef} className={styles.trading__top_form}>
|
||||
<InputPanelItem
|
||||
currencyNames={currencyNames}
|
||||
priceState={orderForm.price}
|
||||
amountState={orderForm.amount}
|
||||
totalState={orderForm.total}
|
||||
buySellState={orderFormType}
|
||||
setBuySellState={setOrderFormType}
|
||||
setPriceFunction={orderForm.onPriceChange}
|
||||
setAmountFunction={orderForm.onAmountChange}
|
||||
setRangeInputValue={orderForm.setRangeInputValue}
|
||||
rangeInputValue={orderForm.rangeInputValue}
|
||||
balance={Number(balance)}
|
||||
priceValid={orderForm.priceValid}
|
||||
amountValid={orderForm.amountValid}
|
||||
totalValid={orderForm.totalValid}
|
||||
totalUsd={orderForm.totalUsd}
|
||||
scrollToOrderList={scrollToOrdersList}
|
||||
onAfter={onAfter}
|
||||
/>
|
||||
</div>
|
||||
{/* <AllTrades
|
||||
currencyNames={currencyNames}
|
||||
filteredTrades={filteredTrades}
|
||||
setTradesType={setTradesType}
|
||||
tradesLoading={tradesLoading}
|
||||
tradesType={tradesType}
|
||||
/>
|
||||
/> */}
|
||||
</div>
|
||||
|
||||
<div className={styles.trading__info}>
|
||||
|
|
@ -213,8 +230,6 @@ function Trading() {
|
|||
userOrders={userOrders}
|
||||
applyTips={applyTips}
|
||||
myOrdersLoading={myOrdersLoading}
|
||||
ordersType={ordersType}
|
||||
setOrdersType={setOrdersType}
|
||||
handleCancelAllOrders={handleCancelAllOrders}
|
||||
matrixAddresses={matrixAddresses}
|
||||
secondAssetUsdPrice={secondAssetUsdPrice}
|
||||
|
|
@ -222,35 +237,6 @@ function Trading() {
|
|||
onAfter={onAfter}
|
||||
/>
|
||||
</div>
|
||||
<div ref={orderFormRef} className={styles.trading__info_createOrders}>
|
||||
{['buy', 'sell'].map((type) => {
|
||||
const isBuy = type === 'buy';
|
||||
const form = isBuy ? buyForm : sellForm;
|
||||
|
||||
return (
|
||||
<InputPanelItem
|
||||
key={type}
|
||||
currencyNames={currencyNames}
|
||||
priceState={form.price}
|
||||
amountState={form.amount}
|
||||
totalState={form.total}
|
||||
buySellValues={buySellValues}
|
||||
buySellState={isBuy ? buySellValues[1] : buySellValues[2]}
|
||||
setPriceFunction={form.onPriceChange}
|
||||
setAmountFunction={form.onAmountChange}
|
||||
setRangeInputValue={form.setRangeInputValue}
|
||||
rangeInputValue={form.rangeInputValue}
|
||||
balance={Number(balance)}
|
||||
priceValid={form.priceValid}
|
||||
amountValid={form.amountValid}
|
||||
totalValid={form.totalValid}
|
||||
totalUsd={form.totalUsd}
|
||||
scrollToOrderList={scrollToOrdersList}
|
||||
onAfter={onAfter}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{alertState && (
|
||||
<Alert
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
display: flex;
|
||||
gap: 20px;
|
||||
padding-bottom: 20px;
|
||||
height: 40dvh;
|
||||
min-height: 380px;
|
||||
max-height: 500px;
|
||||
height: 570px;
|
||||
|
||||
&_chart {
|
||||
width: 100%;
|
||||
|
|
@ -42,17 +40,17 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
&_form {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 415px;
|
||||
}
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 40px;
|
||||
|
||||
&_createOrders {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,4 +50,6 @@
|
|||
--table-tr-hover-color: #172a66;
|
||||
--dex-tooltip-bg: #11316b;
|
||||
--dex-tooltip-border-color: #1f8feb26;
|
||||
}
|
||||
--dex-sell-percentage: #272757;
|
||||
--dex-buy-percentage: #103262;
|
||||
}
|
||||
|
|
@ -50,4 +50,6 @@
|
|||
--table-tr-hover-color: #dcf0ff;
|
||||
--dex-tooltip-bg: #eff8ff;
|
||||
--dex-tooltip-border-color: #1f8feb33;
|
||||
}
|
||||
--dex-sell-percentage: #FCEDED;
|
||||
--dex-buy-percentage: #E5F8F8;
|
||||
}
|
||||
|
|
@ -12,8 +12,7 @@ interface takeOrderClickParams {
|
|||
| React.MouseEvent<HTMLTableRowElement, MouseEvent>;
|
||||
PageOrderData: PageOrderData;
|
||||
pairData: PairDataType | null;
|
||||
buyForm: OrderFormOutput;
|
||||
sellForm: OrderFormOutput;
|
||||
orderForm: OrderFormOutput;
|
||||
balance: string | undefined;
|
||||
scrollToOrderForm: () => void;
|
||||
}
|
||||
|
|
@ -22,8 +21,7 @@ function takeOrderClick({
|
|||
event,
|
||||
PageOrderData,
|
||||
pairData,
|
||||
buyForm,
|
||||
sellForm,
|
||||
orderForm,
|
||||
balance,
|
||||
scrollToOrderForm,
|
||||
}: takeOrderClickParams) {
|
||||
|
|
@ -36,59 +34,31 @@ function takeOrderClick({
|
|||
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: 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: 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,
|
||||
});
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.toDecimalPlaces(fixed).toString();
|
||||
}
|
||||
|
||||
// Remove trailing zeros
|
||||
return fixedValue;
|
||||
return decimalValue.toString();
|
||||
};
|
||||
|
||||
export const localeTimeLeft = (now: number | null, timestamp: number) => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue