import React, {
ChangeEvent, ReactElement, RefObject, useCallback, useMemo, useState,
} from 'react';
import styled from 'styled-components';
import { useSet, useValue } from 'use-change';
import * as t from 'altamoon-types';
import { format } from 'd3-format';
import useBootstrapTooltip from './useBootstrapTooltip';
import {
CUSTOMIZATION, TRADING, ACCOUNT, PHLEGMATIC,
} from './storeSelectors';
const Input = styled.input`
padding: 0.1rem 0.2rem !important;
text-align: center;
background-image: none !important;
&:disabled {
background-color: transparent !important;
}
`;
interface Props {
value: number | null;
isEnabled: boolean;
isPnlPercent?: boolean;
isDefault: boolean;
isNegative?: boolean;
position?: t.TradingPosition;
onChange: (value: number | null) => void;
}
const PRICE_LINE_ID = 'input_focus_phlegmatic_price_line';
const parseNumber = (str: string) => (str && !Number.isNaN(+str) ? +str : null);
const calcPrice = (
isNegative: boolean | undefined,
valueStr: string,
position?: t.TradingPosition,
) => {
const percent = parseNumber(valueStr);
if (!position || percent === null) return 0;
const { entryPrice, leverage } = position;
return entryPrice + ((entryPrice * ((percent / 100) / leverage)) * (isNegative ? -1 : 1) * (position.side === 'SELL' ? -1 : 1));
};
const MiniNumberInput = ({
position: givenPosition, value, isPnlPercent, isDefault, isEnabled, isNegative, onChange,
}: Props): ReactElement => {
const [valueStr, setValueStr] = useState(value?.toString() ?? '');
const setCustomLines = useSet(CUSTOMIZATION, 'customPriceLines');
const defaultSide = useValue(PHLEGMATIC, 'defaultSide');
const currentSymbolPseudoPosition = useValue(TRADING, 'currentSymbolPseudoPosition');
const totalWalletBalance = useValue(ACCOUNT, 'totalWalletBalance');
const [tooltipRef, setTooltip] = useBootstrapTooltip({ trigger: 'focus' });
const position: t.TradingPosition | undefined = useMemo(() => (isDefault
? { ...currentSymbolPseudoPosition, side: defaultSide } as t.TradingPosition
: givenPosition),
[currentSymbolPseudoPosition, defaultSide, givenPosition, isDefault]);
const updateTooltip = useCallback((yValue: number, percent: number | null) => {
if (!isPnlPercent || !position) return;
if (percent === null) {
setTooltip('Incorrect value');
} else {
const baseValue = position?.baseValue ?? 0;
const leverage = position?.leverage ?? 1;
const profit = (isNegative ? -1 : 1) * (position.side === 'SELL' ? -1 : 1)
* (baseValue / leverage)
* (percent / 100);
const profitBalancePercent = (profit / totalWalletBalance) * 100;
setTooltip(`
1 ${position?.baseAsset ?? 'unknown'} = ${format(`.${position?.pricePrecision ?? 0}f`)(yValue)} USDT
${!isDefault ? `
${(profit > 0 ? '+' : '') + profit.toFixed(2)} USDT
${(profitBalancePercent > 0 ? '+' : '') + profitBalancePercent.toFixed(2)}%
on wallet
` : ''}
`.trim());
}
}, [isDefault, isNegative, isPnlPercent, position, setTooltip, totalWalletBalance]);
const onFocus = useCallback(({ target }: ChangeEvent) => {
if (!isPnlPercent || !position) return;
const percent = parseNumber(target.value);
const yValue = calcPrice(isNegative, target.value, position);
setCustomLines((customLines) => [
...customLines.filter(({ id }) => id !== PRICE_LINE_ID),
{
yValue,
isVisible: parseNumber(target.value) !== null,
title: 'Phlegmatic: Input',
id: PRICE_LINE_ID,
color: 'purple',
lineStyle: 'dashed',
},
]);
updateTooltip(yValue, percent);
}, [isNegative, isPnlPercent, position, setCustomLines, updateTooltip]);
const onBlur = useCallback(() => {
if (!isPnlPercent || !position) return;
setCustomLines((customLines) => customLines.filter(({ id }) => id !== PRICE_LINE_ID));
}, [isPnlPercent, position, setCustomLines]);
const onInputChange = useCallback(({ target }: ChangeEvent) => {
const percent = parseNumber(target.value);
setValueStr(target.value);
onChange(percent);
if (!isPnlPercent || !position) return;
const yValue = calcPrice(isNegative, target.value, position);
setCustomLines((customLines) => customLines
.map((customLine) => (customLine.id === PRICE_LINE_ID ? {
...customLine,
yValue,
isVisible: percent !== null,
} : customLine)));
updateTooltip(yValue, percent);
}, [isNegative, isPnlPercent, onChange, position, setCustomLines, updateTooltip]);
return (
}
style={{ width: `${Math.max(30, (valueStr.length + 1) * 10)}px` }}
onChange={onInputChange}
onFocus={onFocus}
onBlur={onBlur}
/>
);
};
export default MiniNumberInput;