-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add confirmation layout * fmt * jsx in return statement Co-authored-by: Nathan Seva <thykof@protonmail.ch> * Revert "jsx in return statement" This reverts commit d06a80a. * rename token balance * move stepsEnum * clean --------- Co-authored-by: Nathan Seva <thykof@protonmail.ch>
- Loading branch information
1 parent
91f2d81
commit a86b14a
Showing
5 changed files
with
286 additions
and
223 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
260 changes: 39 additions & 221 deletions
260
src/pages/IndexPage/Layouts/BridgeRedeemLayout/BridgeRedeemLayout.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,269 +1,87 @@ | ||
import { useState } from 'react'; | ||
import { Button, Money, formatAmount } from '@massalabs/react-ui-kit'; | ||
import Big from 'big.js'; | ||
import { FiRepeat } from 'react-icons/fi'; | ||
import { parseUnits } from 'viem'; | ||
import { useAccount } from 'wagmi'; | ||
import { boxLayout } from './BoxLayout'; | ||
import { ReactNode, useState } from 'react'; | ||
import { Button } from '@massalabs/react-ui-kit'; | ||
import { FeesEstimation } from './FeesEstimation'; | ||
import { WarningNoEth } from './WarningNoEth'; | ||
|
||
import { GetTokensPopUpModal } from '@/components'; | ||
import { ServiceFeeTooltip } from '@/components/ServiceFeeTooltip/ServiceFeeTooltip'; | ||
import { OperationLayout } from './OperationLayout'; | ||
import { ConfirmationLayout } from '../ConfirmationLayout/ConfirmationLayout'; | ||
import useEvmToken from '@/custom/bridge/useEvmToken'; | ||
import { useServiceFee } from '@/custom/bridge/useServiceFee'; | ||
import { useSubmitBridge } from '@/custom/bridge/useSubmitBridge'; | ||
import { useSubmitRedeem } from '@/custom/bridge/useSubmitRedeem'; | ||
import Intl from '@/i18n/i18n'; | ||
import { PendingOperationLayout } from '@/pages'; | ||
import { Status } from '@/store/globalStatusesStore'; | ||
import { | ||
useAccountStore, | ||
useBridgeModeStore, | ||
useGlobalStatusesStore, | ||
useOperationStore, | ||
useTokenStore, | ||
} from '@/store/store'; | ||
import { SIDE } from '@/utils/const'; | ||
import { getAmountToReceive, serviceFeeToPercent } from '@/utils/utils'; | ||
import { useGlobalStatusesStore, useOperationStore } from '@/store/store'; | ||
|
||
interface BridgeRedeemProps { | ||
isBlurred: string; | ||
isButtonDisabled: boolean; | ||
} | ||
|
||
enum StepsEnum { | ||
PENDING = 'pending', | ||
AWAITING_CONFIRMATION = 'confirmation', | ||
} | ||
|
||
export function BridgeRedeemLayout(props: BridgeRedeemProps) { | ||
const { isBlurred, isButtonDisabled } = props; | ||
|
||
const { setAmountError, amountError } = useGlobalStatusesStore(); | ||
|
||
const { tokenBalance: _tokenBalanceEVM, isFetched: isBalanceFetched } = | ||
useEvmToken(); | ||
const { isConnected: isEvmWalletConnected } = useAccount(); | ||
const { tokenBalance: _tokenBalanceEVM } = useEvmToken(); | ||
const { box } = useGlobalStatusesStore(); | ||
const { isMainnet: getIsMainnet } = useBridgeModeStore(); | ||
const isMainnet = getIsMainnet(); | ||
const { | ||
isMassaToEvm, | ||
inputAmount, | ||
outputAmount, | ||
setSide, | ||
setInputAmount, | ||
setOutputAmount, | ||
} = useOperationStore(); | ||
|
||
const [inputField, setInputField] = useState<string>(); | ||
|
||
const { isFetching } = useAccountStore(); | ||
|
||
const { selectedToken: token } = useTokenStore(); | ||
const { serviceFee } = useServiceFee(); | ||
|
||
const [openTokensModal, setOpenTokensModal] = useState<boolean>(false); | ||
const { isMassaToEvm, setInputAmount } = useOperationStore(); | ||
|
||
const massaToEvm = isMassaToEvm(); | ||
|
||
const { handleSubmitBridge } = useSubmitBridge(); | ||
const { handleSubmitRedeem } = useSubmitRedeem(); | ||
|
||
function handlePercent(percent: number) { | ||
if (!token || !isBalanceFetched) return; | ||
const [step, setStep] = useState<StepsEnum>(StepsEnum.PENDING); | ||
const [cta, setCTA] = useState<string>(Intl.t('general.next')); | ||
|
||
if ( | ||
(massaToEvm && token.balance <= 0) || | ||
(!massaToEvm && _tokenBalanceEVM <= 0) | ||
) { | ||
setAmountError(Intl.t('index.approve.error.insufficient-funds')); | ||
return; | ||
} | ||
|
||
const amount = massaToEvm | ||
? formatAmount(token?.balance.toString(), token.decimals, '').full | ||
: formatAmount(_tokenBalanceEVM.toString(), token.decimals, '').full; | ||
|
||
const x = new Big(amount); | ||
const y = new Big(percent); | ||
const res = x.times(y).round(token.decimals).toFixed(); | ||
|
||
const _amount = parseUnits(res, token.decimals); | ||
|
||
setInputAmount(_amount); | ||
setInputField(res); | ||
const amountToReceive = getAmountToReceive(_amount, serviceFee); | ||
setOutputAmount(amountToReceive); | ||
function prevPage() { | ||
setStep(StepsEnum.PENDING); | ||
setCTA(Intl.t('general.next')); | ||
} | ||
|
||
function handleToggleLayout() { | ||
const OperationSteps: Record<StepsEnum, ReactNode> = { | ||
[StepsEnum.PENDING]: <OperationLayout />, | ||
[StepsEnum.AWAITING_CONFIRMATION]: ( | ||
<ConfirmationLayout prevPage={prevPage} /> | ||
), | ||
}; | ||
|
||
function handleSubmission() { | ||
if (step === StepsEnum.PENDING) { | ||
setStep(StepsEnum.AWAITING_CONFIRMATION); | ||
setCTA( | ||
massaToEvm | ||
? Intl.t('index.button.redeem') | ||
: Intl.t('index.button.bridge'), | ||
); | ||
return; | ||
} | ||
massaToEvm ? handleSubmitRedeem() : handleSubmitBridge(); | ||
// sets inputAmount to undefined for next transfer | ||
setInputAmount(undefined); | ||
setOutputAmount(undefined); | ||
setInputField(undefined); | ||
setSide(massaToEvm ? SIDE.EVM_TO_MASSA : SIDE.MASSA_TO_EVM); | ||
} | ||
|
||
function handleGenericSubmit() { | ||
isMassaToEvm() ? handleSubmitRedeem() : handleSubmitBridge(); | ||
// sets input field to undefined for next transfer | ||
setInputField(undefined); | ||
} | ||
|
||
const isOperationPending = box !== Status.None; | ||
|
||
if (isOperationPending) return <PendingOperationLayout />; | ||
|
||
function changeAmount(amount: string) { | ||
if (!token) return; | ||
if (!amount) { | ||
setInputAmount(undefined); | ||
setInputField(undefined); | ||
setOutputAmount(undefined); | ||
return; | ||
} | ||
|
||
const parsedInputAmount = parseUnits(amount, token.decimals); | ||
setInputAmount(parsedInputAmount); | ||
setInputField(amount); | ||
|
||
if (isMassaToEvm()) { | ||
const amountToReceive = getAmountToReceive(parsedInputAmount, serviceFee); | ||
setOutputAmount(amountToReceive); | ||
} else { | ||
setOutputAmount(parsedInputAmount); | ||
} | ||
} | ||
|
||
// Money component formats amount without decimals | ||
return ( | ||
<> | ||
<div | ||
className={`p-10 max-w-3xl w-full border border-tertiary rounded-2xl | ||
bg-secondary/50 text-f-primary mb-5 ${isBlurred}`} | ||
> | ||
<div className="p-6 bg-primary rounded-2xl mb-5"> | ||
<p className="mb-4 mas-body">{Intl.t('index.from')}</p> | ||
{boxLayout().up.header} | ||
{boxLayout().up.wallet} | ||
<div className="mb-4 flex items-center gap-2"> | ||
<div className="w-full"> | ||
<Money | ||
disable={isFetching} | ||
name="amount" | ||
value={inputField || ''} | ||
onValueChange={(o) => changeAmount(o.value)} | ||
placeholder={Intl.t('index.input.placeholder.amount')} | ||
suffix="" | ||
decimalScale={token?.decimals} | ||
error={amountError} | ||
/> | ||
<div className="flex flex-row-reverse"> | ||
<ul className="flex flex-row mas-body2"> | ||
<li | ||
onClick={() => handlePercent(0.25)} | ||
className="mr-3.5 hover:cursor-pointer" | ||
> | ||
25% | ||
</li> | ||
<li | ||
onClick={() => handlePercent(0.5)} | ||
className="mr-3.5 hover:cursor-pointer" | ||
> | ||
50% | ||
</li> | ||
<li | ||
onClick={() => handlePercent(0.75)} | ||
className="mr-3.5 hover:cursor-pointer" | ||
> | ||
75% | ||
</li> | ||
<li | ||
onClick={() => handlePercent(1)} | ||
className="mr-3.5 hover:cursor-pointer" | ||
> | ||
Max | ||
</li> | ||
</ul> | ||
</div> | ||
</div> | ||
<div className="w-1/3 mb-4">{boxLayout().up.token}</div> | ||
</div> | ||
<div className="flex justify-between items-center"> | ||
<div className="flex items-center gap-2"> | ||
{!isMainnet && isEvmWalletConnected && ( | ||
<h3 | ||
className="mas-h3 text-f-disabled-1 underline cursor-pointer" | ||
onClick={() => setOpenTokensModal(true)} | ||
> | ||
{Intl.t('index.get-tokens')} | ||
</h3> | ||
)} | ||
</div> | ||
{boxLayout().up.balance} | ||
</div> | ||
</div> | ||
<div className="mb-5 flex justify-center items-center"> | ||
<Button | ||
disabled={isFetching} | ||
variant="toggle" | ||
onClick={handleToggleLayout} | ||
customClass={`w-12 h-12 inline-block transition ease-in-out delay-10 ${ | ||
massaToEvm ? 'rotate-180' : '' | ||
}`} | ||
> | ||
<FiRepeat size={24} /> | ||
</Button> | ||
</div> | ||
<div className="mb-5 p-6 bg-primary rounded-2xl"> | ||
{isMassaToEvm() ? ( | ||
<div className="flex items-center mb-4 gap-2"> | ||
<p className="mas-body"> | ||
{Intl.t('index.input.placeholder.receive')} | ||
</p> | ||
<ServiceFeeTooltip | ||
inputAmount={ | ||
formatAmount(inputAmount || '0', token?.decimals).full | ||
} | ||
serviceFee={serviceFeeToPercent(serviceFee)} | ||
outputAmount={ | ||
formatAmount(outputAmount || '0', token?.decimals).full | ||
} | ||
symbol={token?.symbol || ''} | ||
/> | ||
</div> | ||
) : ( | ||
<p className="mb-4 mas-body">{Intl.t('index.to')}</p> | ||
)} | ||
{boxLayout().down.header} | ||
{boxLayout().down.wallet} | ||
<div className="mb-4 flex items-center gap-2"> | ||
<div className="w-full"> | ||
<Money | ||
placeholder={Intl.t('index.input.placeholder.receive')} | ||
name="receive" | ||
value={ | ||
formatAmount(outputAmount || '0', token?.decimals).full || '' | ||
} | ||
suffix="" | ||
decimalScale={token?.decimals} | ||
error="" | ||
disable={true} | ||
/> | ||
</div> | ||
<div className="w-1/3">{boxLayout().down.token}</div> | ||
</div> | ||
<WarningNoEth /> | ||
</div> | ||
{OperationSteps[step]} | ||
<div className="mb-5"> | ||
<Button disabled={isButtonDisabled} onClick={handleGenericSubmit}> | ||
{massaToEvm | ||
? Intl.t('index.button.redeem') | ||
: Intl.t('index.button.bridge')} | ||
<Button disabled={isButtonDisabled} onClick={handleSubmission}> | ||
{cta} | ||
</Button> | ||
</div> | ||
<FeesEstimation /> | ||
</div> | ||
|
||
{openTokensModal && ( | ||
<GetTokensPopUpModal setOpenModal={setOpenTokensModal} /> | ||
)} | ||
</> | ||
); | ||
} |
Oops, something went wrong.