MP-1566: Deposit funds modal (#33)
* feat: deposit account modal * style: button default colors to match wireframes * react-query-devtools package added * slider moved to separate component
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { XMarkIcon } from '@heroicons/react/24/solid'
|
||||
import { toast } from 'react-toastify'
|
||||
import * as Slider from '@radix-ui/react-slider'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import Container from 'components/Container'
|
||||
@@ -17,6 +16,7 @@ import Tooltip from 'components/Tooltip'
|
||||
import ContainerSecondary from 'components/ContainerSecondary'
|
||||
import Spinner from 'components/Spinner'
|
||||
import useCalculateMaxBorrowAmount from 'hooks/useCalculateMaxBorrowAmount'
|
||||
import Slider from 'components/Slider'
|
||||
|
||||
const BorrowFunds = ({ tokenDenom, onClose }: any) => {
|
||||
const [amount, setAmount] = useState(0)
|
||||
@@ -113,36 +113,19 @@ const BorrowFunds = ({ tokenDenom, onClose }: any) => {
|
||||
</div>
|
||||
</ContainerSecondary>
|
||||
<ContainerSecondary>
|
||||
<div className="relative mb-4 flex flex-1 items-center">
|
||||
<Slider.Root
|
||||
className="relative flex h-[20px] w-full cursor-pointer touch-none select-none items-center"
|
||||
value={[percentageValue]}
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
onValueChange={(value) => {
|
||||
const decimal = value[0] / 100
|
||||
const tokenDecimals = getTokenDecimals(tokenDenom)
|
||||
// limit decimal precision based on token contract decimals
|
||||
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
||||
<Slider
|
||||
className="mb-6"
|
||||
value={percentageValue}
|
||||
onChange={(value) => {
|
||||
const decimal = value[0] / 100
|
||||
const tokenDecimals = getTokenDecimals(tokenDenom)
|
||||
// limit decimal precision based on token contract decimals
|
||||
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
||||
|
||||
setAmount(newAmount)
|
||||
}}
|
||||
>
|
||||
<Slider.Track className="relative h-[6px] grow rounded-full bg-gray-400">
|
||||
<Slider.Range className="absolute h-[100%] rounded-full bg-blue-600" />
|
||||
</Slider.Track>
|
||||
<Slider.Thumb className="flex h-[20px] w-[20px] items-center justify-center rounded-full bg-white !outline-none">
|
||||
<div className="relative top-5 text-xs">{percentageValue.toFixed(0)}%</div>
|
||||
</Slider.Thumb>
|
||||
</Slider.Root>
|
||||
<button
|
||||
className="ml-4 rounded-md bg-blue-600 py-1 px-2 text-xs font-semibold text-white"
|
||||
onClick={() => setAmount(maxValue)}
|
||||
>
|
||||
MAX
|
||||
</button>
|
||||
</div>
|
||||
setAmount(newAmount)
|
||||
}}
|
||||
onMaxClick={() => setAmount(maxValue)}
|
||||
/>
|
||||
</ContainerSecondary>
|
||||
<ContainerSecondary className="flex items-center justify-between">
|
||||
<div className="flex">
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { XMarkIcon } from '@heroicons/react/24/solid'
|
||||
import { toast } from 'react-toastify'
|
||||
import * as Slider from '@radix-ui/react-slider'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import Container from 'components/Container'
|
||||
@@ -13,6 +12,7 @@ import BigNumber from 'bignumber.js'
|
||||
import useAllBalances from 'hooks/useAllBalances'
|
||||
import ContainerSecondary from 'components/ContainerSecondary'
|
||||
import Spinner from 'components/Spinner'
|
||||
import Slider from 'components/Slider'
|
||||
|
||||
const RepayFunds = ({ tokenDenom, amount: repayAmount, onClose }: any) => {
|
||||
const [amount, setAmount] = useState(0)
|
||||
@@ -91,36 +91,19 @@ const RepayFunds = ({ tokenDenom, amount: repayAmount, onClose }: any) => {
|
||||
</div>
|
||||
</ContainerSecondary>
|
||||
<ContainerSecondary>
|
||||
<div className="relative mb-4 flex flex-1 items-center">
|
||||
<Slider.Root
|
||||
className="relative flex h-[20px] w-full cursor-pointer touch-none select-none items-center"
|
||||
value={[percentageValue]}
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
onValueChange={(value) => {
|
||||
const decimal = value[0] / 100
|
||||
const tokenDecimals = getTokenDecimals(tokenDenom)
|
||||
// limit decimal precision based on token contract decimals
|
||||
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
||||
<Slider
|
||||
className="mb-6"
|
||||
value={percentageValue}
|
||||
onChange={(value) => {
|
||||
const decimal = value[0] / 100
|
||||
const tokenDecimals = getTokenDecimals(tokenDenom)
|
||||
// limit decimal precision based on token contract decimals
|
||||
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
||||
|
||||
setAmount(newAmount)
|
||||
}}
|
||||
>
|
||||
<Slider.Track className="relative h-[6px] grow rounded-full bg-gray-400">
|
||||
<Slider.Range className="absolute h-[100%] rounded-full bg-blue-600" />
|
||||
</Slider.Track>
|
||||
<Slider.Thumb className="flex h-[20px] w-[20px] items-center justify-center rounded-full bg-white !outline-none">
|
||||
<div className="relative top-5 text-xs">{percentageValue.toFixed(0)}%</div>
|
||||
</Slider.Thumb>
|
||||
</Slider.Root>
|
||||
<button
|
||||
className="ml-4 rounded-md bg-blue-600 py-1 px-2 text-xs font-semibold text-white"
|
||||
onClick={() => setAmount(maxValue)}
|
||||
>
|
||||
MAX
|
||||
</button>
|
||||
</div>
|
||||
setAmount(newAmount)
|
||||
}}
|
||||
onMaxClick={() => setAmount(maxValue)}
|
||||
/>
|
||||
</ContainerSecondary>
|
||||
</div>
|
||||
<Button className="w-full" onClick={handleSubmit} disabled={isSubmitDisabled}>
|
||||
|
||||
@@ -12,7 +12,7 @@ const Button = React.forwardRef<any, Props>(
|
||||
<button
|
||||
ref={ref}
|
||||
onClick={onClick}
|
||||
className={`overflow-hidden text-ellipsis rounded-3xl bg-green-500 py-2 px-5 text-sm font-semibold text-white ${className} ${
|
||||
className={`overflow-hidden text-ellipsis rounded-md bg-blue-500 py-2 px-5 text-sm font-semibold text-white ${className} ${
|
||||
disabled ? 'opacity-40' : ''
|
||||
}`}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
import * as Slider from '@radix-ui/react-slider'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { Switch } from '@headlessui/react'
|
||||
import useLocalStorageState from 'use-local-storage-state'
|
||||
|
||||
import Button from '../Button'
|
||||
import useAllowedCoins from 'hooks/useAllowedCoins'
|
||||
import useDepositCreditAccount from 'hooks/useDepositCreditAccount'
|
||||
import useCreditManagerStore from 'stores/useCreditManagerStore'
|
||||
import useAllBalances from 'hooks/useAllBalances'
|
||||
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
||||
import ContainerSecondary from 'components/ContainerSecondary'
|
||||
|
||||
const FundAccount = () => {
|
||||
const [amount, setAmount] = useState(0)
|
||||
const [selectedToken, setSelectedToken] = useState('')
|
||||
|
||||
const selectedAccount = useCreditManagerStore((s) => s.selectedAccount)
|
||||
|
||||
const [lendAssets, setLendAssets] = useLocalStorageState(`lendAssets_${selectedAccount}`, {
|
||||
defaultValue: false,
|
||||
})
|
||||
|
||||
const { data: balancesData } = useAllBalances()
|
||||
const { data: allowedCoinsData, isLoading: isLoadingAllowedCoins } = useAllowedCoins()
|
||||
const { mutate } = useDepositCreditAccount(
|
||||
selectedAccount || '',
|
||||
selectedToken,
|
||||
BigNumber(amount)
|
||||
.times(10 ** getTokenDecimals(selectedToken))
|
||||
.toNumber()
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (allowedCoinsData && allowedCoinsData.length > 0) {
|
||||
// initialize selected token when allowedCoins fetch data is available
|
||||
setSelectedToken(allowedCoinsData[0])
|
||||
}
|
||||
}, [allowedCoinsData])
|
||||
|
||||
const walletAmount = useMemo(() => {
|
||||
if (!selectedToken) return 0
|
||||
|
||||
return BigNumber(balancesData?.find((balance) => balance.denom === selectedToken)?.amount ?? 0)
|
||||
.div(10 ** getTokenDecimals(selectedToken))
|
||||
.toNumber()
|
||||
}, [balancesData, selectedToken])
|
||||
|
||||
const handleValueChange = (value: number) => {
|
||||
if (value > walletAmount) {
|
||||
setAmount(walletAmount)
|
||||
return
|
||||
}
|
||||
|
||||
setAmount(value)
|
||||
}
|
||||
|
||||
const maxValue = walletAmount
|
||||
const percentageValue = isNaN(amount) ? 0 : (amount * 100) / maxValue
|
||||
|
||||
return (
|
||||
<>
|
||||
<ContainerSecondary className="mb-2 p-3">
|
||||
<p className="mb-6 text-sm">
|
||||
Transfer assets from your injective wallet to your Mars credit account. If you don’t have
|
||||
any assets in your injective wallet use the injective bridge to transfer funds to your
|
||||
injective wallet.
|
||||
</p>
|
||||
{isLoadingAllowedCoins ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
<>
|
||||
<div className="mb-4 text-sm">
|
||||
<div className="mb-1 flex justify-between">
|
||||
<div>Asset:</div>
|
||||
<select
|
||||
className="bg-transparent"
|
||||
onChange={(e) => {
|
||||
setSelectedToken(e.target.value)
|
||||
|
||||
if (e.target.value !== selectedToken) setAmount(0)
|
||||
}}
|
||||
>
|
||||
{allowedCoinsData?.map((entry) => (
|
||||
<option key={entry} value={entry}>
|
||||
{getTokenSymbol(entry)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<div>Amount:</div>
|
||||
<input
|
||||
type="number"
|
||||
className="border border-black/50 bg-transparent px-2"
|
||||
value={amount}
|
||||
onChange={(e) => handleValueChange(e.target.valueAsNumber)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-sm">In wallet: {walletAmount.toLocaleString()}</p>
|
||||
{/* SLIDER - initial implementation to test functionality */}
|
||||
{/* TODO: will need to be revamped later on */}
|
||||
<div className="relative mb-6 flex flex-1 items-center">
|
||||
<Slider.Root
|
||||
className="relative flex h-[20px] w-full cursor-pointer touch-none select-none items-center"
|
||||
value={[percentageValue]}
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
onValueChange={(value) => {
|
||||
const decimal = value[0] / 100
|
||||
const tokenDecimals = getTokenDecimals(selectedToken)
|
||||
// limit decimal precision based on token contract decimals
|
||||
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
||||
|
||||
setAmount(newAmount)
|
||||
}}
|
||||
>
|
||||
<Slider.Track className="relative h-[6px] grow rounded-full bg-gray-400">
|
||||
<Slider.Range className="absolute h-[100%] rounded-full bg-blue-600" />
|
||||
</Slider.Track>
|
||||
<Slider.Thumb className="flex h-[20px] w-[20px] items-center justify-center rounded-full bg-white !outline-none">
|
||||
<div className="relative top-5 text-xs">{percentageValue.toFixed(0)}%</div>
|
||||
</Slider.Thumb>
|
||||
</Slider.Root>
|
||||
<button
|
||||
className="ml-4 rounded-md bg-blue-600 py-1 px-2 text-xs font-semibold text-white"
|
||||
onClick={() => setAmount(maxValue)}
|
||||
>
|
||||
MAX
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</ContainerSecondary>
|
||||
<ContainerSecondary className="mb-2 flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="font-bold">Lending Assets</h3>
|
||||
<div className="text-sm text-[#585A74]/50">Lend assets from account to earn yield.</div>
|
||||
</div>
|
||||
|
||||
<Switch
|
||||
checked={lendAssets}
|
||||
onChange={setLendAssets}
|
||||
className={`${
|
||||
lendAssets ? 'bg-blue-600' : 'bg-gray-400'
|
||||
} relative inline-flex h-6 w-11 items-center rounded-full`}
|
||||
>
|
||||
<span
|
||||
className={`${
|
||||
lendAssets ? 'translate-x-6' : 'translate-x-1'
|
||||
} inline-block h-4 w-4 transform rounded-full bg-white transition`}
|
||||
/>
|
||||
</Switch>
|
||||
</ContainerSecondary>
|
||||
<Button
|
||||
className="w-full !rounded-lg"
|
||||
onClick={() => mutate()}
|
||||
disabled={amount === 0 || !amount}
|
||||
>
|
||||
Fund
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default FundAccount
|
||||
@@ -7,14 +7,14 @@ import useCreditManagerStore from 'stores/useCreditManagerStore'
|
||||
import useWalletStore from 'stores/useWalletStore'
|
||||
import useCreditAccountPositions from 'hooks/useCreditAccountPositions'
|
||||
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
||||
import FundAccount from './FundAccount'
|
||||
import useTokenPrices from 'hooks/useTokenPrices'
|
||||
import useAccountStats from 'hooks/useAccountStats'
|
||||
import useMarkets from 'hooks/useMarkets'
|
||||
import ContainerSecondary from 'components/ContainerSecondary'
|
||||
import FundAccountModal from 'components/FundAccountModal'
|
||||
|
||||
const CreditManager = () => {
|
||||
const [isFund, setIsFund] = useState(false)
|
||||
const [showFundWalletModal, setShowFundWalletModal] = useState(false)
|
||||
|
||||
const address = useWalletStore((s) => s.address)
|
||||
const selectedAccount = useCreditManagerStore((s) => s.selectedAccount)
|
||||
@@ -48,95 +48,85 @@ const CreditManager = () => {
|
||||
|
||||
return (
|
||||
<div className="absolute inset-0 left-auto w-[400px] border-l border-white/20 bg-background-2 p-2">
|
||||
<ContainerSecondary className="mb-2">
|
||||
{isFund ? (
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="font-bold">Fund Account</h3>
|
||||
<Button className="rounded-md" onClick={() => setIsFund(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
<ContainerSecondary className="mb-2 flex gap-3">
|
||||
<Button className="flex-1 rounded-md" onClick={() => setShowFundWalletModal(true)}>
|
||||
Fund
|
||||
</Button>
|
||||
<Button
|
||||
className="flex-1 rounded-md"
|
||||
onClick={() => alert('TODO')}
|
||||
disabled={!positionsData || positionsData.coins.length === 0}
|
||||
>
|
||||
Withdraw
|
||||
</Button>
|
||||
</ContainerSecondary>
|
||||
<ContainerSecondary className="mb-2 text-sm">
|
||||
<div className="mb-1 flex justify-between">
|
||||
<div>Total Position:</div>
|
||||
<div className="font-semibold">{formatCurrency(accountStats?.totalPosition ?? 0)}</div>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<div>Total Liabilities:</div>
|
||||
<div className="font-semibold">{formatCurrency(accountStats?.totalDebt ?? 0)}</div>
|
||||
</div>
|
||||
</ContainerSecondary>
|
||||
<ContainerSecondary>
|
||||
<h4 className="font-bold">Balances</h4>
|
||||
{isLoadingPositions ? (
|
||||
<div>Loading...</div>
|
||||
) : (
|
||||
<div className="flex gap-3">
|
||||
<Button className="flex-1 rounded-md" onClick={() => setIsFund(true)}>
|
||||
Fund
|
||||
</Button>
|
||||
<Button className="flex-1 rounded-md" onClick={() => alert('TODO')}>
|
||||
Withdraw
|
||||
</Button>
|
||||
</div>
|
||||
<>
|
||||
<div className="flex text-xs font-semibold">
|
||||
<div className="flex-1">Asset</div>
|
||||
<div className="flex-1">Value</div>
|
||||
<div className="flex-1">Size</div>
|
||||
<div className="flex-1">APY</div>
|
||||
</div>
|
||||
{positionsData?.coins.map((coin) => (
|
||||
<div key={coin.denom} className="flex text-xs text-black/40">
|
||||
<div className="flex-1">{getTokenSymbol(coin.denom)}</div>
|
||||
<div className="flex-1">
|
||||
{formatCurrency(getTokenTotalUSDValue(coin.amount, coin.denom))}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
{BigNumber(coin.amount)
|
||||
.div(10 ** getTokenDecimals(coin.denom))
|
||||
.toNumber()
|
||||
.toLocaleString(undefined, {
|
||||
maximumFractionDigits: getTokenDecimals(coin.denom),
|
||||
})}
|
||||
</div>
|
||||
<div className="flex-1">-</div>
|
||||
</div>
|
||||
))}
|
||||
{positionsData?.debts.map((coin) => (
|
||||
<div key={coin.denom} className="flex text-xs text-red-500">
|
||||
<div className="flex-1 text-black/40">{getTokenSymbol(coin.denom)}</div>
|
||||
<div className="flex-1">
|
||||
-{formatCurrency(getTokenTotalUSDValue(coin.amount, coin.denom))}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
-
|
||||
{BigNumber(coin.amount)
|
||||
.div(10 ** getTokenDecimals(coin.denom))
|
||||
.toNumber()
|
||||
.toLocaleString(undefined, {
|
||||
maximumFractionDigits: 6,
|
||||
})}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
-{(Number(marketsData?.[coin.denom].borrow_rate) * 100).toFixed(1)}%
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</ContainerSecondary>
|
||||
{isFund ? (
|
||||
<FundAccount />
|
||||
) : (
|
||||
<>
|
||||
<ContainerSecondary className="mb-2 text-sm">
|
||||
<div className="mb-1 flex justify-between">
|
||||
<div>Total Position:</div>
|
||||
<div className="font-semibold">
|
||||
{formatCurrency(accountStats?.totalPosition ?? 0)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<div>Total Liabilities:</div>
|
||||
<div className="font-semibold">{formatCurrency(accountStats?.totalDebt ?? 0)}</div>
|
||||
</div>
|
||||
</ContainerSecondary>
|
||||
<ContainerSecondary>
|
||||
<h4 className="font-bold">Balances</h4>
|
||||
{isLoadingPositions ? (
|
||||
<div>Loading...</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex text-xs font-semibold">
|
||||
<div className="flex-1">Asset</div>
|
||||
<div className="flex-1">Value</div>
|
||||
<div className="flex-1">Size</div>
|
||||
<div className="flex-1">APY</div>
|
||||
</div>
|
||||
{positionsData?.coins.map((coin) => (
|
||||
<div key={coin.denom} className="flex text-xs text-black/40">
|
||||
<div className="flex-1">{getTokenSymbol(coin.denom)}</div>
|
||||
<div className="flex-1">
|
||||
{formatCurrency(getTokenTotalUSDValue(coin.amount, coin.denom))}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
{BigNumber(coin.amount)
|
||||
.div(10 ** getTokenDecimals(coin.denom))
|
||||
.toNumber()
|
||||
.toLocaleString(undefined, {
|
||||
maximumFractionDigits: getTokenDecimals(coin.denom),
|
||||
})}
|
||||
</div>
|
||||
<div className="flex-1">-</div>
|
||||
</div>
|
||||
))}
|
||||
{positionsData?.debts.map((coin) => (
|
||||
<div key={coin.denom} className="flex text-xs text-red-500">
|
||||
<div className="flex-1 text-black/40">{getTokenSymbol(coin.denom)}</div>
|
||||
<div className="flex-1">
|
||||
-{formatCurrency(getTokenTotalUSDValue(coin.amount, coin.denom))}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
-
|
||||
{BigNumber(coin.amount)
|
||||
.div(10 ** getTokenDecimals(coin.denom))
|
||||
.toNumber()
|
||||
.toLocaleString(undefined, {
|
||||
maximumFractionDigits: 6,
|
||||
})}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
-{(Number(marketsData?.[coin.denom].borrow_rate) * 100).toFixed(1)}%
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</ContainerSecondary>
|
||||
</>
|
||||
)}
|
||||
<FundAccountModal
|
||||
key={`fundModal_${selectedAccount}`}
|
||||
show={showFundWalletModal}
|
||||
onClose={() => setShowFundWalletModal(false)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
import Image from 'next/image'
|
||||
import { Transition, Dialog, Switch } from '@headlessui/react'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { toast } from 'react-toastify'
|
||||
import useLocalStorageState from 'use-local-storage-state'
|
||||
|
||||
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
|
||||
import ContainerSecondary from './ContainerSecondary'
|
||||
import useCreditManagerStore from 'stores/useCreditManagerStore'
|
||||
import Button from './Button'
|
||||
import Spinner from './Spinner'
|
||||
import useAllBalances from 'hooks/useAllBalances'
|
||||
import useAllowedCoins from 'hooks/useAllowedCoins'
|
||||
import useDepositCreditAccount from 'hooks/useDepositCreditAccount'
|
||||
import Slider from 'components/Slider'
|
||||
|
||||
const FundAccountModal = ({ show, onClose }: any) => {
|
||||
const [amount, setAmount] = useState(0)
|
||||
const [selectedToken, setSelectedToken] = useState('')
|
||||
|
||||
const selectedAccount = useCreditManagerStore((s) => s.selectedAccount)
|
||||
|
||||
const [lendAssets, setLendAssets] = useLocalStorageState(`lendAssets_${selectedAccount}`, {
|
||||
defaultValue: false,
|
||||
})
|
||||
|
||||
const { data: balancesData } = useAllBalances()
|
||||
const { data: allowedCoinsData, isLoading: isLoadingAllowedCoins } = useAllowedCoins()
|
||||
const { mutate, isLoading } = useDepositCreditAccount(
|
||||
selectedAccount || '',
|
||||
selectedToken,
|
||||
BigNumber(amount)
|
||||
.times(10 ** getTokenDecimals(selectedToken))
|
||||
.toNumber(),
|
||||
{
|
||||
onSuccess: () => {
|
||||
setAmount(0)
|
||||
toast.success(`${amount} ${getTokenSymbol(selectedToken)} successfully Deposited`)
|
||||
onClose()
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (allowedCoinsData && allowedCoinsData.length > 0) {
|
||||
// initialize selected token when allowedCoins fetch data is available
|
||||
setSelectedToken(allowedCoinsData[0])
|
||||
}
|
||||
}, [allowedCoinsData])
|
||||
|
||||
const walletAmount = useMemo(() => {
|
||||
if (!selectedToken) return 0
|
||||
|
||||
return BigNumber(balancesData?.find((balance) => balance.denom === selectedToken)?.amount ?? 0)
|
||||
.div(10 ** getTokenDecimals(selectedToken))
|
||||
.toNumber()
|
||||
}, [balancesData, selectedToken])
|
||||
|
||||
const handleValueChange = (value: number) => {
|
||||
if (value > walletAmount) {
|
||||
setAmount(walletAmount)
|
||||
return
|
||||
}
|
||||
|
||||
setAmount(value)
|
||||
}
|
||||
|
||||
const maxValue = walletAmount
|
||||
const percentageValue = isNaN(amount) ? 0 : (amount * 100) / maxValue
|
||||
|
||||
return (
|
||||
<Transition appear show={show} as={React.Fragment}>
|
||||
<Dialog as="div" className="relative z-10" onClose={onClose}>
|
||||
<Transition.Child
|
||||
as={React.Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="fixed inset-0 bg-black bg-opacity-80" />
|
||||
</Transition.Child>
|
||||
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4">
|
||||
<Transition.Child
|
||||
as={React.Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Dialog.Panel className="flex min-h-[520px] w-full max-w-3xl transform overflow-hidden rounded-2xl bg-[#585A74] align-middle shadow-xl transition-all">
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 z-40 grid place-items-center bg-black/50">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex flex-1 flex-col items-start justify-between bg-[#4A4C60] p-6">
|
||||
<div>
|
||||
<p className="text-bold mb-3 text-xs uppercase text-white/50">About</p>
|
||||
<h4 className="mb-4 text-xl leading-8">
|
||||
Bringing the next generation of video creation to the Metaverse.
|
||||
<br />
|
||||
Powered by deep-learning.
|
||||
</h4>
|
||||
</div>
|
||||
<Image src="/logo.svg" alt="mars" width={150} height={50} />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-1 flex-col p-4">
|
||||
<Dialog.Title as="h3" className="mb-4 text-center font-medium">
|
||||
Fund Account {selectedAccount}
|
||||
</Dialog.Title>
|
||||
<ContainerSecondary className="mb-2 p-3">
|
||||
<p className="mb-6 text-sm text-[#585A74]/50">
|
||||
Transfer assets from your injective wallet to your Mars credit account. If you
|
||||
don’t have any assets in your injective wallet use the injective bridge to
|
||||
transfer funds to your injective wallet.
|
||||
</p>
|
||||
{isLoadingAllowedCoins ? (
|
||||
<p>Loading...</p>
|
||||
) : (
|
||||
<>
|
||||
<div className="mb-2 rounded-md border border-[#585A74] text-sm">
|
||||
<div className="mb-1 flex justify-between border-b border-[#585A74] p-2">
|
||||
<div className="font-bold">Asset:</div>
|
||||
<select
|
||||
className="bg-transparent outline-0"
|
||||
onChange={(e) => {
|
||||
setSelectedToken(e.target.value)
|
||||
|
||||
if (e.target.value !== selectedToken) setAmount(0)
|
||||
}}
|
||||
value={selectedToken}
|
||||
>
|
||||
{allowedCoinsData?.map((entry) => (
|
||||
<option key={entry} value={entry}>
|
||||
{getTokenSymbol(entry)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex justify-between p-2">
|
||||
<div className="font-bold">Amount:</div>
|
||||
<input
|
||||
type="number"
|
||||
className="bg-transparent text-right outline-0"
|
||||
value={amount}
|
||||
min="0"
|
||||
onChange={(e) => handleValueChange(e.target.valueAsNumber)}
|
||||
onBlur={(e) => {
|
||||
if (e.target.value === '') setAmount(0)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p className="mb-2 text-sm">In wallet: {walletAmount.toLocaleString()}</p>
|
||||
<Slider
|
||||
className="mb-6"
|
||||
value={percentageValue}
|
||||
onChange={(value) => {
|
||||
const decimal = value[0] / 100
|
||||
const tokenDecimals = getTokenDecimals(selectedToken)
|
||||
// limit decimal precision based on token contract decimals
|
||||
const newAmount = Number((decimal * maxValue).toFixed(tokenDecimals))
|
||||
|
||||
setAmount(newAmount)
|
||||
}}
|
||||
onMaxClick={() => setAmount(maxValue)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</ContainerSecondary>
|
||||
<ContainerSecondary className="mb-2 flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="font-bold">Lending Assets</h3>
|
||||
<div className="text-sm text-[#585A74]/50">
|
||||
Lend assets from account to earn yield.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Switch
|
||||
checked={lendAssets}
|
||||
onChange={setLendAssets}
|
||||
className={`${
|
||||
lendAssets ? 'bg-blue-600' : 'bg-gray-400'
|
||||
} relative inline-flex h-6 w-11 items-center rounded-full`}
|
||||
>
|
||||
<span
|
||||
className={`${
|
||||
lendAssets ? 'translate-x-6' : 'translate-x-1'
|
||||
} inline-block h-4 w-4 transform rounded-full bg-white transition`}
|
||||
/>
|
||||
</Switch>
|
||||
</ContainerSecondary>
|
||||
<Button
|
||||
className="mt-auto w-full"
|
||||
onClick={() => mutate()}
|
||||
disabled={amount === 0 || !amount}
|
||||
>
|
||||
Fund Account
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition>
|
||||
)
|
||||
}
|
||||
|
||||
export default FundAccountModal
|
||||
@@ -0,0 +1,39 @@
|
||||
import React from 'react'
|
||||
import * as RadixSlider from '@radix-ui/react-slider'
|
||||
|
||||
type Props = {
|
||||
className?: string
|
||||
value: number
|
||||
onChange: (value: number[]) => void
|
||||
onMaxClick: () => void
|
||||
}
|
||||
|
||||
const Slider = ({ className, value, onChange, onMaxClick }: Props) => {
|
||||
return (
|
||||
<div className={`relative flex flex-1 items-center ${className || ''}`}>
|
||||
<RadixSlider.Root
|
||||
className="relative flex h-[20px] w-full cursor-pointer touch-none select-none items-center"
|
||||
value={[value]}
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
onValueChange={(value) => onChange(value)}
|
||||
>
|
||||
<RadixSlider.Track className="relative h-[6px] grow rounded-full bg-gray-400">
|
||||
<RadixSlider.Range className="absolute h-[100%] rounded-full bg-blue-600" />
|
||||
</RadixSlider.Track>
|
||||
<RadixSlider.Thumb className="flex h-[20px] w-[20px] items-center justify-center rounded-full bg-white !outline-none">
|
||||
<div className="relative top-5 text-xs">{value.toFixed(0)}%</div>
|
||||
</RadixSlider.Thumb>
|
||||
</RadixSlider.Root>
|
||||
<button
|
||||
className="ml-4 rounded-md bg-blue-600 py-1 px-2 text-xs font-semibold text-white"
|
||||
onClick={onMaxClick}
|
||||
>
|
||||
MAX
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Slider
|
||||
@@ -18,7 +18,7 @@ const WalletPopover = ({ children }: { children: React.ReactNode }) => {
|
||||
|
||||
return (
|
||||
<Popover className="relative">
|
||||
<Popover.Button as={Button} className="w-[200px]">
|
||||
<Popover.Button as={Button} className="w-[200px] !rounded-3xl !bg-green-500">
|
||||
{children}
|
||||
</Popover.Button>
|
||||
|
||||
@@ -79,7 +79,10 @@ const Wallet = () => {
|
||||
{address ? (
|
||||
<WalletPopover>{formatWalletAddress(address)}</WalletPopover>
|
||||
) : (
|
||||
<Button className="w-[200px]" onClick={() => setShowConnectModal(true)}>
|
||||
<Button
|
||||
className="w-[200px] !rounded-3xl !bg-green-500"
|
||||
onClick={() => setShowConnectModal(true)}
|
||||
>
|
||||
Connect Wallet
|
||||
</Button>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user