import {
AvailableAmount,
DenomArr,
MainContainer,
Select,
Slider,
} from 'src/components';
import { RootState } from 'src/redux/store';
import useSetActiveAddress from 'src/hooks/useSetActiveAddress';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { CYBER } from 'src/utils/config';
import { PATTERN_CYBER } from 'src/constants/app';
import { useQueryClient } from 'src/contexts/queryClient';
import {
getDisplayAmount,
getDisplayAmountReverce,
reduceBalances,
} from 'src/utils/utils';
import { OptionSelect, SelectOption } from 'src/components/Select';
import { useIbcDenom } from 'src/contexts/ibcDenom';
import BigNumber from 'bignumber.js';
import { Option } from 'src/types';
import { ObjKeyValue } from 'src/types/data';
import { createSearchParams, useSearchParams } from 'react-router-dom';
import { useAppSelector } from 'src/redux/hooks';
import useAccountsPassports from 'src/features/passport/hooks/useAccountsPassports';
import {
Col,
GridContainer,
TeleportContainer,
} from '../components/containers/Containers';
import ActionBar from './actionBar.send';
import DataSendTxs from './components/dataSendTxs/DataSendTxs';
import {
AccountInput,
InputMemo,
InputNumberDecimalScale,
} from '../components/Inputs';
import useGetSendTxsByAddressByLcd from '../hooks/useGetSendTxsByAddressByLcd';
import { useTeleport } from '../Teleport.context';
const tokenDefaultValue = CYBER.DENOM_CYBER;
function Send() {
const queryClient = useQueryClient();
const { traseDenom } = useIbcDenom();
const { defaultAccount } = useAppSelector((state: RootState) => state.pocket);
useAccountsPassports();
const { addressActive } = useSetActiveAddress(defaultAccount);
const { totalSupplyProofList, accountBalances, refreshBalances } =
useTeleport();
const [update, setUpdate] = useState(0);
const [recipient, setRecipient] = useState<string | undefined>(undefined);
const [searchParams, setSearchParams] = useSearchParams();
// const dataSendTxs = useGetSendTxsByAddressByType(
// addressActive,
// 'cosmos.bank.v1beta1.MsgSend'
// );
const dataSendTxs = useGetSendTxsByAddressByLcd(addressActive, recipient);
const [tokenSelect, setTokenSelect] = useState<string>(tokenDefaultValue);
const [tokenAmount, setTokenAmount] = useState<string>('');
const [recipientBalances, setRecipientBalances] =
useState<Option<ObjKeyValue>>(undefined);
const [recipientTokenABalances, setRecipientTokenABalances] = useState(0);
const [memoValue, setMemoValue] = useState<string>('');
const [isExceeded, setIsExceeded] = useState<boolean>(false);
const firstEffectOccured = useRef(false);
const [tokenACoinDecimals, setTokenACoinDecimals] = useState<number>(0);
const [tokenABalance, setTokenABalance] = useState<number>(0);
useEffect(() => {
if (firstEffectOccured.current) {
// eslint-disable-next-line react-hooks/exhaustive-deps
const query = {
token: tokenSelect,
recipient: '',
amount: '',
};
if (recipient) {
query.recipient = recipient;
}
if (Number(tokenAmount) > 0) {
query.amount = tokenAmount;
}
setSearchParams(createSearchParams(query), { replace: true });
} else {
firstEffectOccured.current = true;
const param = Object.fromEntries(searchParams.entries());
if (Object.keys(param).length > 0) {
const { token, recipient, amount } = param;
setTokenSelect(token);
if (recipient) {
setRecipient(recipient);
}
if (amount && Number(amount) > 0) {
setTokenAmount(amount);
}
}
}
}, [tokenSelect, recipient, setSearchParams, searchParams, tokenAmount]);
useEffect(() => {
const [{ coinDecimals }] = traseDenom(tokenSelect);
setTokenACoinDecimals(coinDecimals);
}, [tokenSelect, traseDenom]);
// setTokenABalance
useEffect(() => {
if (accountBalances) {
setTokenABalance(accountBalances[tokenSelect] || 0);
}
}, [tokenSelect, accountBalances]);
const validInputAmountToken = useMemo(() => {
if (Number(tokenAmount) > 0) {
const amountToken = parseFloat(
getDisplayAmountReverce(tokenAmount, tokenACoinDecimals)
);
return amountToken > tokenABalance;
}
return false;
}, [tokenAmount, tokenACoinDecimals, tokenABalance]);
useEffect(() => {
const validTokenAmount = !validInputAmountToken && Number(tokenAmount) > 0;
const validRecipient = recipient && recipient.match(PATTERN_CYBER);
setIsExceeded(!(validRecipient && validTokenAmount));
}, [recipient, validInputAmountToken, tokenAmount]);
useEffect(() => {
(async () => {
setRecipientBalances(undefined);
const isInit = queryClient && recipient && recipient.match(PATTERN_CYBER);
if (!isInit) {
return;
}
const getAllBalancesPromise = await queryClient.getAllBalances(recipient);
const dataReduceBalances = reduceBalances(getAllBalancesPromise);
setRecipientBalances(dataReduceBalances);
})();
}, [queryClient, recipient, update]);
useEffect(() => {
setRecipientTokenABalances(
recipientBalances ? recipientBalances[tokenSelect] || 0 : 0
);
}, [recipientBalances, tokenSelect]);
const reduceOptions = useMemo(
() =>
totalSupplyProofList
? Object.keys(totalSupplyProofList).map((key) => ({
value: key,
text: (
<DenomArr denomValue={key} onlyText tooltipStatusText={false} />
),
img: <DenomArr denomValue={key} onlyImg tooltipStatusImg={false} />,
}))
: [],
[totalSupplyProofList]
);
const setPercentageBalanceHook = useCallback(
(value: number) => {
if (tokenABalance) {
const amount = new BigNumber(tokenABalance)
.multipliedBy(value)
.dividedBy(100)
.dp(tokenACoinDecimals, BigNumber.ROUND_FLOOR)
.toNumber();
setTokenAmount(getDisplayAmount(amount, tokenACoinDecimals));
}
},
[tokenABalance, tokenACoinDecimals]
);
const getPercentsOfToken = useCallback(() => {
const amountTokenA = getDisplayAmountReverce(
tokenAmount,
tokenACoinDecimals
);
return tokenABalance > 0
? new BigNumber(amountTokenA)
.dividedBy(tokenABalance)
.multipliedBy(100)
.toNumber()
: 0;
}, [tokenAmount, tokenABalance, tokenACoinDecimals]);
const updateFunc = useCallback(() => {
setUpdate((item) => item + 1);
dataSendTxs.refetch();
refreshBalances();
setMemoValue('');
}, [dataSendTxs, refreshBalances]);
const amountTokenChange = useCallback(
(tokenBalance: number, type: 'sender' | 'recipient') => {
let amount = new BigNumber(
getDisplayAmount(tokenBalance, tokenACoinDecimals)
);
let changeAmount = new BigNumber(tokenAmount);
if (type === 'sender') {
changeAmount = changeAmount.multipliedBy(-1);
}
if (changeAmount.comparedTo(0)) {
amount = new BigNumber(amount).plus(changeAmount);
}
return amount.comparedTo(0) >= 0 ? amount.toNumber() : 0;
},
[tokenAmount, tokenACoinDecimals]
);
const stateActionBar = {
tokenAmount,
tokenSelect,
recipient,
updateFunc,
isExceeded,
memoValue,
};
return (
<>
<MainContainer width="62%">
<TeleportContainer>
<Select
valueSelect={CYBER.CHAIN_ID}
currentValue={CYBER.CHAIN_ID}
disabled
options={[
{
value: CYBER.CHAIN_ID,
text: CYBER.CHAIN_ID,
img: (
<DenomArr
denomValue={CYBER.CHAIN_ID}
onlyImg
type="network"
tooltipStatusImg={false}
/>
),
},
]}
width="100%"
// disabled
title="choose network"
/>
<InputMemo value={memoValue} onChangeValue={setMemoValue} />
<AccountInput recipient={recipient} setRecipient={setRecipient} />
<GridContainer>
<Col>
<InputNumberDecimalScale
value={tokenAmount}
onValueChange={(value) => setTokenAmount(value)}
title="choose amount to send"
validAmount={validInputAmountToken}
tokenSelect={tokenSelect}
/>
<AvailableAmount
amountToken={amountTokenChange(tokenABalance, 'sender')}
title={tokenAmount.length === 0 ? 'you have' : 'you will have'}
/>
</Col>
<Col>
<Select
valueSelect={tokenSelect}
currentValue={
<OptionSelect
text="choose"
img={<DenomArr denomValue="choose" onlyImg />}
value=""
bgrImg
/>
}
onChangeSelect={(item: string) => setTokenSelect(item)}
width="100%"
options={reduceOptions}
title="choose token to send"
/>
<AvailableAmount
title={
tokenAmount.length === 0
? 'recipient have'
: 'recipient will have'
}
amountToken={amountTokenChange(
recipientTokenABalances,
'recipient'
)}
/>
</Col>
</GridContainer>
<Slider
valuePercents={getPercentsOfToken()}
onChange={setPercentageBalanceHook}
/>
</TeleportContainer>
<TeleportContainer>
<DataSendTxs dataSendTxs={dataSendTxs} accountUser={addressActive} />
</TeleportContainer>
</MainContainer>
<ActionBar stateActionBar={stateActionBar} />
</>
);
}
export default Send;