Transaction loader component (#449)

* feat: added transaction loader screen to modals

* tidy: refactor

* 🐛 fix: borrow not updating vault values (#436)

*  Merge FundAccount and AccountFund (#431)

*  Merge FundAccount and AccountFund

* fix build

* 🐛 fundAccount not showing, small typos/text corrections

* MP-3376: overpay on repay (#438)

* MP-3376: overpay on repay

* fix: remove Buffer and fix NaN on useSpring

* feat: added transaction loader screen to modals

* fix: updated AccountFundContent

* fix: fixed the animated-loader issues

* 🐛 UNSAFE_COMPONENT error (#439)

* 🐛 UNSAFE_COMPONENT error

* 🐛 fix unit tests for react-helmet-async

* Small text fixes (#440)

* 🐛 text fix on fund for new account

* 🐛 make toggle account-wide lending on new-account

* Styling alert dialog (#441)

* 🐛 text fix on fund for new account

* 🐛 make toggle account-wide lending on new-account

* 💅🏼Update styling of alertDialogs

* Fixes bob (#443)

* 🐛 Trading chart title

* 🐛 Trading chart title

* 🐛 fix incorrect vault deposit amounts

* 🐛 fix incorrect vault borrow calc

* 🧽 run format

* 🧽 fix comments

* 🧽 update code owners

* Build(deps): bump bignumber.js from 9.1.1 to 9.1.2 (#444)

Bumps [bignumber.js](https://github.com/MikeMcl/bignumber.js) from 9.1.1 to 9.1.2.
- [Release notes](https://github.com/MikeMcl/bignumber.js/releases)
- [Changelog](https://github.com/MikeMcl/bignumber.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/MikeMcl/bignumber.js/compare/v9.1.1...v9.1.2)

---
updated-dependencies:
- dependency-name: bignumber.js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Build(deps-dev): bump @types/react from 18.2.19 to 18.2.21 (#448)

Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.19 to 18.2.21.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Build(deps): bump next from 13.4.9 to 13.4.19 (#446)

Bumps [next](https://github.com/vercel/next.js) from 13.4.9 to 13.4.19.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v13.4.9...v13.4.19)

---
updated-dependencies:
- dependency-name: next
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Build(deps-dev): bump @types/node from 20.4.8 to 20.6.0 (#447)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.4.8 to 20.6.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Linkie Link <linkielink.dev@gmail.com>

* feat: refactored the toast responses (#442)

* feat: refactored the toast responses

* fix: fixed the map return

* feat: added a recent transaction center

* tidy: removed logs

* fix: fixed autolend

* feat: added global lending on first account funding

* fix: added endOfLine setting

* feat: added eslint warnings for lineEnds

* fix: made the vault message generic

* feat: added transaction loader screen to modals

* 🐛 fix: borrow not updating vault values (#436)

*  Merge FundAccount and AccountFund (#431)

*  Merge FundAccount and AccountFund

* fix build

* 🐛 fundAccount not showing, small typos/text corrections

* feat: added transaction loader screen to modals

* fix: updated AccountFundContent

* fix: fixed the animated-loader issues

* tidy: refactor

* fix: set pendingTransaction inside the broadcast slice

* fix: fixed the pipeline

* fix: setting showTxLoader

* fix: fixed the pipeline

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
Linkie Link 2023-09-11 12:51:44 +02:00 committed by GitHub
parent 7547f9e148
commit 1bf93670a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 411 additions and 96 deletions

View File

@ -24,7 +24,7 @@ export default function AccordionContent(props: Props) {
<div
onClick={() => toggleOpen(props.index)}
className={classNames(
'mb-0 flex cursor-pointer items-center justify-between border-t border-white/10 bg-white/10 p-4 text-white',
'mb-0 flex hover:cursor-pointer items-center justify-between border-t border-white/10 bg-white/10 p-4 text-white',
'group-[&:first-child]:border-t-0 group-[[open]]:border-b',
'[&::marker]:hidden [&::marker]:content-[""]',
isOpen && 'border-b [&:first-child]:border-t-0',

View File

@ -169,7 +169,7 @@ export default function Index(props: Props) {
onClick={header.column.getToggleSortingHandler()}
className={classNames(
'p-2',
header.column.getCanSort() && 'cursor-pointer',
header.column.getCanSort() && 'hover:cursor-pointer',
header.id === 'symbol' ? 'text-left' : 'text-right',
)}
>

View File

@ -106,7 +106,7 @@ function AccountDetails(props: Props) {
</Text>
<FormattedNumber
className={'w-full text-center text-2xs'}
amount={leverage.toNumber()}
amount={isNaN(leverage.toNumber()) ? 0 : leverage.toNumber()}
options={{ maxDecimals: 2, minDecimals: 2, suffix: 'x' }}
animate
/>

View File

@ -36,11 +36,11 @@ export default function AccountFundContent(props: Props) {
const deposit = useStore((s) => s.deposit)
const accounts = useStore((s) => s.accounts)
const walletAssetModal = useStore((s) => s.walletAssetsModal)
const showTxLoader = useStore((s) => s.showTxLoader)
const [lendAssets, setLendAssets] = useLocalStorage<boolean>(
LEND_ASSETS_KEY,
DEFAULT_SETTINGS.lendAssets,
)
const [isFunding, setIsFunding] = useToggle(false)
const [fundingAssets, setFundingAssets] = useState<BNCoin[]>([])
const { data: marketAssets } = useMarketAssets()
const { data: walletBalances } = useWalletBalances(props.address)
@ -75,21 +75,19 @@ export default function AccountFundContent(props: Props) {
}, [selectedDenoms])
const handleClick = useCallback(async () => {
setIsFunding(true)
if (!props.accountId) return
const result = await deposit({
accountId: props.accountId,
coins: fundingAssets,
lend: isLending,
})
setIsFunding(false)
if (result)
useStore.setState({
fundAndWithdrawModal: null,
walletAssetsModal: null,
focusComponent: null,
})
}, [setIsFunding, props.accountId, deposit, fundingAssets, isLending])
}, [props.accountId, deposit, fundingAssets, isLending])
useEffect(() => {
if (BN(baseBalance).isLessThan(defaultFee.amount[0].amount)) {
@ -173,7 +171,7 @@ export default function AccountFundContent(props: Props) {
max={balance}
balances={balances}
maxText='Max'
disabled={isFunding}
disabled={showTxLoader}
/>
</div>
)
@ -186,7 +184,7 @@ export default function AccountFundContent(props: Props) {
rightIcon={<Plus />}
iconClassName='w-3'
onClick={handleSelectAssetsClick}
disabled={isFunding}
disabled={showTxLoader}
/>
<DepositCapMessage
action='fund'
@ -205,7 +203,7 @@ export default function AccountFundContent(props: Props) {
className='w-full mt-4'
text='Fund account'
disabled={!hasFundingAssets || depositCapReachedCoins.length > 0}
showProgressIndicator={isFunding}
showProgressIndicator={showTxLoader}
onClick={handleClick}
color={props.isFullPage ? 'tertiary' : undefined}
size={props.isFullPage ? 'lg' : undefined}

View File

@ -67,7 +67,7 @@ export default function AccountSummary(props: Props) {
<Item label='Leverage' classes='flex-1'>
<FormattedNumber
className='text-sm'
amount={leverage.toNumber()}
amount={isNaN(leverage.toNumber()) ? 0 : leverage.toNumber()}
options={{ minDecimals: 2, suffix: 'x' }}
/>
</Item>

View File

@ -64,8 +64,9 @@ const Button = React.forwardRef(function Button(
return classNames(
'relative z-1 flex items-center',
'cursor-pointer appearance-none break-normal outline-none',
'appearance-none break-normal outline-none',
'text-white transition-all',
'hover:cursor-pointer',
!reduceMotion && 'transition-color',
buttonClasses,
buttonVariantClasses[variant],

View File

@ -100,7 +100,7 @@ export default function VaultExpanded(props: Props) {
return (
<tr
key={props.row.id}
className='transition-colors cursor-pointer bg-black/20'
className='hover:cursor-pointer bg-black/20 transition-colors'
onClick={(e) => {
e.preventDefault()
const isExpanded = props.row.getIsExpanded()

View File

@ -13,7 +13,7 @@ export const VaultRow = (props: AssetRowProps) => {
key={props.row.id}
className={classNames(
'bg-white/3 group/row border-b border-t border-white/5 transition-colors hover:bg-white/5',
vault.status && 'cursor-pointer',
vault.status && 'hover:cursor-pointer',
props.row.getIsExpanded() && 'is-expanded',
)}
onClick={(e) => {

View File

@ -254,7 +254,7 @@ export const VaultTable = (props: Props) => {
onClick={header.column.getToggleSortingHandler()}
className={classNames(
'px-4 py-3',
header.column.getCanSort() && 'cursor-pointer',
header.column.getCanSort() && 'hover:cursor-pointer',
header.id === 'symbol' ? 'text-left' : 'text-right',
)}
>

View File

@ -47,7 +47,7 @@ function AssetListTableRow<TData>(props: Props<TData>) {
<tr
key={props.rowData.id}
className={classNames(
'cursor-pointer transition-colors',
'hover:cursor-pointer transition-colors',
props.rowData.getIsExpanded() ? 'bg-black/20' : 'bg-white/0 hover:bg-white/5',
)}

View File

@ -55,7 +55,7 @@ function AssetListTable<TData>(props: Props<TData>) {
onClick={header.column.getToggleSortingHandler()}
className={classNames(
'px-4 py-3',
header.column.getCanSort() && 'cursor-pointer',
header.column.getCanSort() && 'hover:cursor-pointer',
header.id === 'symbol' ? 'text-left' : 'text-right',
{
'w-32': header.id === 'manage',

View File

@ -3,6 +3,8 @@ import { ReactNode, useEffect, useRef } from 'react'
import EscButton from 'components/Button/EscButton'
import Card from 'components/Card'
import TransactionLoader from 'components/TransactionLoader'
import useStore from 'store'
interface Props {
header: string | ReactNode
@ -14,14 +16,17 @@ interface Props {
contentClassName?: string
modalClassName?: string
onClose: () => void
hideTxLoader?: boolean
}
export default function Modal(props: Props) {
const ref: React.RefObject<HTMLDialogElement> = useRef(null)
const modalClassName = props.modalClassName ?? 'max-w-modal'
const showTxLoader = useStore((s) => s.showTxLoader)
function onClose() {
ref.current?.close()
useStore.setState({ showTxLoader: false })
props.onClose()
}
@ -36,6 +41,7 @@ export default function Modal(props: Props) {
return () => {
dialog?.removeAttribute('open')
dialog?.close()
useStore.setState({ showTxLoader: false })
document.body.classList.remove('h-screen', 'overflow-hidden')
}
}, [])
@ -54,7 +60,7 @@ export default function Modal(props: Props) {
>
<Card
className={classNames(
'relative flex max-w-full flex-1 bg-white/5 backdrop-blur-3xl',
'flex max-w-full flex-1 bg-white/5 backdrop-blur-3xl',
props.className,
)}
>
@ -63,8 +69,12 @@ export default function Modal(props: Props) {
{!props.hideCloseBtn && <EscButton onClick={props.onClose} />}
</div>
<div
className={classNames(props.contentClassName, 'flex-1 overflow-y-scroll scrollbar-hide')}
className={classNames(
props.contentClassName,
'flex-1 overflow-y-scroll scrollbar-hide relative',
)}
>
{showTxLoader && !props.hideTxLoader && <TransactionLoader />}
{props.children ? props.children : props.content}
</div>
</Card>

View File

@ -1,4 +1,4 @@
import { useCallback, useMemo, useState } from 'react'
import { useCallback, useMemo } from 'react'
import { useLocation, useNavigate, useParams } from 'react-router-dom'
import AssetBalanceRow from 'components/AssetBalanceRow'
@ -30,17 +30,14 @@ function AccountDeleteModal(props: Props) {
const { pathname } = useLocation()
const { address } = useParams()
const { debts, vaults, id: accountId } = modal || {}
const [isConfirming, setIsConfirming] = useState(false)
const closeDeleteAccountModal = useCallback(() => {
useStore.setState({ accountDeleteModal: null })
}, [])
const deleteAccountHandler = useCallback(async () => {
setIsConfirming(true)
const options = { accountId: modal.id, lends: modal.lends }
const isSuccess = await deleteAccount(options)
setIsConfirming(false)
if (isSuccess) {
navigate(getRoute(getPage(pathname), address))
closeDeleteAccountModal()
@ -113,7 +110,6 @@ function AccountDeleteModal(props: Props) {
{depositsAndLends.map((position, index) => {
const coin = BNCoin.fromDenomAndBigNumber(position.denom, position.amount)
const asset = getAssetByDenom(position.denom)
if (!asset) return null
return <AssetBalanceRow key={index} asset={asset} coin={coin} />
})}

View File

@ -23,9 +23,7 @@ interface Props {
function AlertDialog(props: Props) {
const { title, icon, description, negativeButton, positiveButton } = props.config
const [isConfirming, setIsConfirming] = useState(false)
const handleButtonClick = (button?: AlertDialogButton) => {
button?.onClick && button.onClick()
props.close()
@ -42,8 +40,9 @@ function AlertDialog(props: Props) {
return (
<Modal
onClose={props.close}
hideTxLoader
header={
<div className='grid h-12 w-12 place-items-center rounded-sm bg-white/5'>
<div className='grid w-12 h-12 rounded-sm place-items-center bg-white/5'>
{icon ?? <ExclamationMarkCircled width={18} />}
</div>
}

View File

@ -86,7 +86,7 @@ export default function AssetSelectTable(props: Props) {
onClick={header.column.getToggleSortingHandler()}
className={classNames(
'p-2',
header.column.getCanSort() && 'cursor-pointer',
header.column.getCanSort() && 'hover:cursor-pointer',
header.id === 'symbol' ? 'text-left' : 'text-right',
)}
>
@ -125,7 +125,7 @@ export default function AssetSelectTable(props: Props) {
return (
<tr
key={row.id}
className='cursor-pointer text-white/60'
className='hover:cursor-pointer text-white/60'
onClick={() => row.toggleSelected()}
>
{row.getVisibleCells().map((cell) => {

View File

@ -55,7 +55,7 @@ export default function BorrowModalController() {
function BorrowModal(props: Props) {
const { modal, account } = props
const [amount, setAmount] = useState(BN_ZERO)
const [isConfirming, setIsConfirming] = useToggle()
const showTxLoader = useStore((s) => s.showTxLoader)
const [borrowToWallet, setBorrowToWallet] = useToggle()
const borrow = useStore((s) => s.borrow)
const repay = useStore((s) => s.repay)
@ -71,12 +71,10 @@ function BorrowModal(props: Props) {
function resetState() {
setAmount(BN_ZERO)
setIsConfirming(false)
}
async function onConfirmClick() {
if (!asset) return
setIsConfirming(true)
let result
const { lend } = getDepositAndLendCoinsToSpend(
BNCoin.fromDenomAndBigNumber(asset.denom, amount),
@ -97,7 +95,6 @@ function BorrowModal(props: Props) {
})
}
setIsConfirming(false)
if (result) {
resetState()
useStore.setState({ borrowModal: null })
@ -226,7 +223,7 @@ function BorrowModal(props: Props) {
max={max}
className='w-full'
maxText='Max'
disabled={isConfirming}
disabled={showTxLoader}
/>
{!isRepay && (
<>
@ -242,7 +239,7 @@ function BorrowModal(props: Props) {
name='borrow-to-wallet'
checked={borrowToWallet}
onChange={setBorrowToWallet}
disabled={isConfirming}
disabled={showTxLoader}
/>
</div>
</>
@ -251,7 +248,7 @@ function BorrowModal(props: Props) {
<Button
onClick={onConfirmClick}
className='w-full'
showProgressIndicator={isConfirming}
showProgressIndicator={showTxLoader}
disabled={amount.isZero()}
text={isRepay ? 'Repay' : 'Borrow'}
rightIcon={<ArrowRight />}

View File

@ -28,7 +28,7 @@ export default function WithdrawFromAccount(props: Props) {
ASSETS.find(byDenom(account.deposits[0]?.denom || account.lends[0]?.denom)) ?? ASSETS[0]
const withdraw = useStore((s) => s.withdraw)
const [withdrawWithBorrowing, setWithdrawWithBorrowing] = useToggle()
const [isConfirming, setIsConfirming] = useToggle()
const showTxLoader = useStore((s) => s.showTxLoader)
const [currentAsset, setCurrentAsset] = useState(defaultAsset)
const [amount, setAmount] = useState(BN_ZERO)
const { simulateWithdraw } = useUpdatedAccount(account)
@ -63,8 +63,6 @@ export default function WithdrawFromAccount(props: Props) {
}
async function onConfirm() {
setIsConfirming(true)
const coins = [
{
coin: BNCoin.fromDenomAndBigNumber(currentAsset.denom, amount),
@ -89,7 +87,6 @@ export default function WithdrawFromAccount(props: Props) {
reclaims,
})
setIsConfirming(false)
if (result) {
resetState()
useStore.setState({ fundAndWithdrawModal: null })
@ -126,7 +123,7 @@ export default function WithdrawFromAccount(props: Props) {
accountId={account.id}
hasSelect
maxText='Max'
disabled={isConfirming}
disabled={showTxLoader}
/>
<Divider className='my-6' />
<div className='flex flex-wrap w-full'>
@ -141,14 +138,14 @@ export default function WithdrawFromAccount(props: Props) {
name='borrow-to-wallet'
checked={withdrawWithBorrowing}
onChange={setWithdrawWithBorrowing}
disabled={isConfirming}
disabled={showTxLoader}
/>
</div>
</div>
</div>
<Button
onClick={onConfirm}
showProgressIndicator={isConfirming}
showProgressIndicator={showTxLoader}
className='w-full'
text={'Withdraw'}
rightIcon={<ArrowRight />}

View File

@ -4,7 +4,6 @@ import AssetAmountSelectActionModal from 'components/Modals/AssetAmountSelectAct
import DetailsHeader from 'components/Modals/LendAndReclaim/DetailsHeader'
import useCurrentAccount from 'hooks/useCurrentAccount'
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
import useToggle from 'hooks/useToggle'
import { useUpdatedAccount } from 'hooks/useUpdatedAccount'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
@ -27,7 +26,7 @@ function LendAndReclaimModal({ currentAccount, config }: Props) {
const lend = useStore((s) => s.lend)
const reclaim = useStore((s) => s.reclaim)
const { close } = useLendAndReclaimModal()
const [isConfirming, setIsConfirming] = useToggle()
const showTxLoader = useStore((s) => s.showTxLoader)
const { simulateLending } = useUpdatedAccount(currentAccount)
const { data, action } = config
@ -47,8 +46,6 @@ function LendAndReclaimModal({ currentAccount, config }: Props) {
const handleAction = useCallback(
async (value: BigNumber, isMax: boolean) => {
setIsConfirming(true)
const coin = BNCoin.fromDenomAndBigNumber(asset.denom, value)
const options = {
accountId: currentAccount.id,
@ -56,20 +53,17 @@ function LendAndReclaimModal({ currentAccount, config }: Props) {
isMax,
}
await (isLendAction ? lend : reclaim)(options)
setIsConfirming(false)
close()
},
[asset.denom, close, currentAccount.id, isLendAction, lend, reclaim, setIsConfirming],
[asset.denom, close, currentAccount.id, isLendAction, lend, reclaim],
)
return (
<AssetAmountSelectActionModal
asset={asset}
contentHeader={<DetailsHeader data={data} />}
coinBalances={coinBalances}
actionButtonText={actionText}
showProgressIndicator={isConfirming}
showProgressIndicator={showTxLoader}
title={`${actionText} ${asset.symbol}`}
onClose={close}
onAction={handleAction}

View File

@ -1,4 +1,3 @@
import { useState } from 'react'
import { useParams } from 'react-router-dom'
import Button from 'components/Button'
@ -13,12 +12,11 @@ interface Props {
export default function UnlockModalContent(props: Props) {
const unlock = useStore((s) => s.unlock)
const [isWating, setIsConfirming] = useState(false)
const showTxLoader = useStore((s) => s.showTxLoader)
const { accountId } = useParams()
async function onConfirm() {
if (!accountId) return
setIsConfirming(true)
await unlock({
accountId: accountId,
vault: props.depositedVault,
@ -33,14 +31,14 @@ export default function UnlockModalContent(props: Props) {
<Text className='mt-2 text-white/60'>
{`Are you sure you want to unlock this position? The unlocking period will take ${props.depositedVault.lockup.duration} ${props.depositedVault.lockup.timeframe}.`}
</Text>
<div className='mt-10 flex flex-row-reverse justify-between'>
<div className='flex flex-row-reverse justify-between mt-10'>
<Button
text='Yes'
color='tertiary'
className='px-6'
rightIcon={<YesIcon />}
onClick={onConfirm}
showProgressIndicator={isWating}
showProgressIndicator={showTxLoader}
/>
<Button
text='No'
@ -49,7 +47,7 @@ export default function UnlockModalContent(props: Props) {
rightIcon={<NoIcon />}
tabIndex={1}
onClick={props.onClose}
disabled={isWating}
disabled={showTxLoader}
/>
</div>
</>

View File

@ -40,7 +40,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
const { data: prices } = usePrices()
const vaultModal = useStore((s) => s.vaultModal)
const depositIntoVault = useStore((s) => s.depositIntoVault)
const [isConfirming, setIsConfirming] = useState(false)
const showTxLoader = useStore((s) => s.showTxLoader)
const updatedAccount = useStore((s) => s.updatedAccount)
const { computeMaxBorrowAmount } = useHealthComputer(updatedAccount)
const [percentage, setPercentage] = useState<number>(0)
@ -145,7 +145,6 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
async function onConfirm() {
if (!updatedAccount || !vaultModal) return
setIsConfirming(true)
const isSuccess = await depositIntoVault({
accountId: updatedAccount.id,
actions: props.depositActions,
@ -153,7 +152,6 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
borrowings: props.borrowings,
isCreate: vaultModal.isCreate,
})
setIsConfirming(false)
if (isSuccess) {
useStore.setState({ vaultModal: null })
}
@ -175,12 +173,12 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
maxText='Max Borrow'
onChange={(amount) => updateAssets(coin.denom, amount)}
onDelete={() => onDelete(coin.denom)}
disabled={isConfirming}
disabled={showTxLoader}
/>
)
})}
{props.borrowings.length === 1 && (
<Slider onChange={onChangeSlider} value={percentage} disabled={isConfirming} />
<Slider onChange={onChangeSlider} value={percentage} disabled={showTxLoader} />
)}
{props.borrowings.length === 0 && (
<div className='flex items-center gap-4 py-2'>
@ -198,7 +196,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
text='Select borrow assets +'
color='tertiary'
onClick={addAsset}
disabled={isConfirming}
disabled={showTxLoader}
/>
<DepositCapMessage
@ -235,7 +233,7 @@ export default function VaultBorrowings(props: VaultBorrowingsProps) {
color='primary'
text='Deposit'
rightIcon={<ArrowRight />}
showProgressIndicator={isConfirming}
showProgressIndicator={showTxLoader}
disabled={!props.depositActions.length || props.depositCapReachedCoins.length > 0}
/>
</div>

View File

@ -1,4 +1,3 @@
import { useState } from 'react'
import { useParams } from 'react-router-dom'
import Button from 'components/Button'
@ -16,7 +15,7 @@ import { demagnify } from 'utils/formatters'
export default function WithdrawFromVaultsModal() {
const modal = useStore((s) => s.withdrawFromVaultsModal)
const { accountId } = useParams()
const [isConfirming, setIsConfirming] = useState(false)
const showTxLoader = useStore((s) => s.showTxLoader)
const withdrawFromVaults = useStore((s) => s.withdrawFromVaults)
const baseCurrency = useStore((s) => s.baseCurrency)
@ -26,12 +25,10 @@ export default function WithdrawFromVaultsModal() {
async function withdrawHandler() {
if (!accountId || !modal) return
setIsConfirming(true)
await withdrawFromVaults({
accountId: accountId,
vaults: modal,
})
setIsConfirming(false)
onClose()
}
@ -50,7 +47,7 @@ export default function WithdrawFromVaultsModal() {
contentClassName='p-4'
>
{modal ? (
<div className='flex w-full flex-wrap gap-4'>
<div className='flex flex-wrap w-full gap-4'>
{modal.map((vault) => {
const positionValue = vault.values.primary.plus(vault.values.secondary)
const coin = BNCoin.fromDenomAndBigNumber(baseCurrency.denom, positionValue)
@ -61,7 +58,7 @@ export default function WithdrawFromVaultsModal() {
return (
<div className='flex items-center gap-4' key={vault.unlockId}>
<VaultLogo vault={vault} />
<div className='flex flex-1 flex-wrap'>
<div className='flex flex-wrap flex-1'>
<Text className='w-full'>{vault.name}</Text>
<Text size='sm' className='w-full text-white/50'>
Unlocked
@ -71,13 +68,13 @@ export default function WithdrawFromVaultsModal() {
<DisplayCurrency coin={coin} className='w-full text-right' />
<FormattedNumber
amount={demagnify(vault.amounts.primary, primaryAsset)}
className='w-full text-right text-sm text-white/50'
className='w-full text-sm text-right text-white/50'
options={{ suffix: ` ${vault.symbols.primary}` }}
animate
/>
<FormattedNumber
amount={demagnify(vault.amounts.secondary, secondaryAsset)}
className='w-full text-right text-sm text-white/50'
className='w-full text-sm text-right text-white/50'
options={{ suffix: ` ${vault.symbols.secondary}` }}
animate
/>
@ -86,9 +83,9 @@ export default function WithdrawFromVaultsModal() {
)
})}
<Button
showProgressIndicator={isConfirming}
showProgressIndicator={showTxLoader}
onClick={withdrawHandler}
className='mt-4 w-full'
className='w-full mt-4'
text='Withdraw from all'
/>
</div>

View File

@ -155,7 +155,7 @@ export default function NumberInput(props: Props) {
onBlur={props.onBlur}
disabled={props.disabled}
className={classNames(
'w-full cursor-pointer appearance-none border-none bg-transparent text-right outline-none',
'w-full hover:cursor-pointer appearance-none border-none bg-transparent text-right outline-none',
props.className,
)}
style={props.style}

View File

@ -1,5 +1,5 @@
import { ChangeEvent, useCallback } from 'react'
import classNames from 'classnames'
import { ChangeEvent, useCallback } from 'react'
import InputOverlay from 'components/RangeInput/InputOverlay'
@ -60,7 +60,7 @@ const className = {
legendWrapper: 'flex w-full justify-between text-xs text-opacity-50 text-white font-bold',
inputWrapper: 'relative h-[30px]',
input: `
relative w-full appearance-none bg-transparent cursor-pointer
relative w-full appearance-none bg-transparent hover:cursor-pointer
[&::-webkit-slider-runnable-track]:bg-white
[&::-webkit-slider-runnable-track]:bg-opacity-20

View File

@ -90,9 +90,9 @@ export default function Slider(props: Props) {
value={props.value}
onChange={handleSliderClick}
onMouseDown={handleShowTooltip}
className='absolute z-2 w-full cursor-pointer appearance-none bg-transparent [&::-webkit-slider-thumb]:h-3 [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:appearance-none'
className='absolute z-2 w-full hover:cursor-pointer appearance-none bg-transparent [&::-webkit-slider-thumb]:h-3 [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:appearance-none'
/>
<div className='absolute flex w-full items-center gap-1'>
<div className='absolute flex items-center w-full gap-1'>
<Mark
onClick={props.onChange}
value={0}
@ -142,12 +142,12 @@ export default function Slider(props: Props) {
<div ref={nodeRef} className='absolute z-20 leading-3'>
<div
className={
'z-20 h-3 w-3 rotate-45 cursor-pointer rounded-xs border-[2px] border-white bg-martian-red'
'z-20 h-3 w-3 rotate-45 hover:cursor-pointer rounded-xs border-[2px] border-white bg-martian-red'
}
/>
{(showTooltip || isDragging) && (
<div className='absolute -top-8 left-1/2 -translate-x-1/2 rounded-xs bg-martian-red px-2 py-[2px] text-xs'>
<OverlayMark className='absolute -bottom-2 left-1/2 -z-1 h-2 -translate-x-1/2 text-martian-red' />
<OverlayMark className='absolute h-2 -translate-x-1/2 -bottom-2 left-1/2 -z-1 text-martian-red' />
{props.value.toFixed(0)}%
</div>
)}
@ -193,9 +193,9 @@ function Track(props: TrackProps) {
}
return (
<div className='relative h-1 flex-1 overflow-hidden rounded-sm bg-transparent'>
<div className='absolute z-1 h-3 bg-martian-red ' style={{ width: `${percentage}%` }} />
<div className='absolute h-3 w-full bg-white/20' />
<div className='relative flex-1 h-1 overflow-hidden bg-transparent rounded-sm'>
<div className='absolute h-3 z-1 bg-martian-red ' style={{ width: `${percentage}%` }} />
<div className='absolute w-full h-3 bg-white/20' />
</div>
)
}

View File

@ -28,7 +28,7 @@ export default function Switch(props: Props) {
<label
htmlFor={props.name}
className={classNames(
'isolate flex cursor-pointer items-center justify-between overflow-hidden',
'isolate flex hover:cursor-pointer items-center justify-between overflow-hidden',
'relative h-5 w-10 rounded-full bg-white/20 shadow-sm',
'before:content-[" "] before:absolute before:left-[1px] before:top-[1px]',
'before:z-1 before:m-0.5 before:h-3.5 before:w-3.5 before:rounded-full before:bg-white before:transition-transform',

View File

@ -35,7 +35,7 @@ export const Tooltip = (props: Props) => {
<span
className={classNames(
props.underline &&
'border-b-1 cursor-pointer border border-x-0 border-t-0 border-dashed border-white/50 hover:border-transparent',
'border-b-1 hover:cursor-pointer border border-x-0 border-t-0 border-dashed border-white/50 hover:border-transparent',
!reduceMotion && 'transition-all',
props.className,
)}
@ -45,7 +45,7 @@ export const Tooltip = (props: Props) => {
) : (
<span
className={classNames(
'inline-block w-[18px] cursor-pointer opacity-40 hover:opacity-80',
'inline-block w-[18px] hover:cursor-pointer opacity-40 hover:opacity-80',
props.className,
)}
>

View File

@ -42,5 +42,5 @@ export default function AccountDetailsCard() {
const className = {
tabWrapper: 'flex w-full items-center bg-white/10 pt-4 pl-4 font-semibold',
tab: 'mr-4 pb-3 cursor-pointer select-none flex flex-row border-b-2 border-pink border-solid',
tab: 'mr-4 pb-3 hover:cursor-pointer select-none flex flex-row border-b-2 border-pink border-solid',
}

View File

@ -88,6 +88,6 @@ const className = {
maxButtonLabel: 'font-bold text-xs',
maxValue: 'font-bold text-xs text-white text-opacity-60 mx-1',
maxButton:
'cursor-pointer select-none bg-white bg-opacity-20 text-2xs !leading-3 font-bold py-0.5 px-1.5 rounded',
'hover:cursor-pointer select-none bg-white bg-opacity-20 text-2xs !leading-3 font-bold py-0.5 px-1.5 rounded',
assetValue: 'text-xs text-white text-opacity-60 mt-2',
}

View File

@ -47,7 +47,7 @@ export default function OrderTypeSelector(props: Props) {
const className = {
wrapper: 'flex flex-1 flex-row px-3 pt-4',
tab: 'mr-4 pb-2 cursor-pointer select-none flex flex-row',
tab: 'mr-4 pb-2 hover:cursor-pointer select-none flex flex-row',
selectedTab: 'border-b-2 border-pink border-solid',
disabledTab: 'opacity-20 pointer-events-none',
infoCircle: 'w-4 h-4 ml-2 mt-1',

View File

@ -0,0 +1,307 @@
import classNames from 'classnames'
import Text from 'components/Text'
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
import { REDUCE_MOTION_KEY } from 'constants/localStore'
import useLocalStorage from 'hooks/useLocalStorage'
export default function TransactionLoader() {
const [reduceMotion] = useLocalStorage<boolean>(REDUCE_MOTION_KEY, DEFAULT_SETTINGS.reduceMotion)
return (
<>
<div className='absolute z-50 flex flex-wrap items-center content-center justify-center w-full h-full text-white bg-black/80'>
<div className='w-[120px] h-[120px]'>
<svg version='1.1' x='0px' y='0px' viewBox='0 0 120 120'>
<path
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[500ms]',
)}
fill='none'
stroke='currentColor'
strokeWidth='1'
strokeMiterlimit='10'
d='M104.5,27.7L92.3,15.5L77,7.7L60,5
L43,7.7l-15.3,7.8L15.5,27.7L7.7,43L5,60l2.7,17l7.8,15.3l12.2,12.2l15.3,7.8l17,2.7l17-2.7l15.3-7.8l12.2-12.2l7.8-15.3l2.7-17
l-2.7-17L104.5,27.7z'
/>
<line
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[700ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
x1='60'
y1='60'
x2='27.7'
y2='15.5'
/>
<line
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[900ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
x1='60'
y1='60'
x2='92.3'
y2='15.5'
/>
<line
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[1100ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
x1='112.3'
y1='77'
x2='60'
y2='60'
/>
<line
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[1300ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
x1='60'
y1='115'
x2='60'
y2='60'
/>
<line
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[1500ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
x1='7.7'
y1='77'
x2='60'
y2='60'
/>
<polygon
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[1800ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
points='47.5,42.9 72.3,43 80.1,66.5 60,81.1
39.8,66.5 '
/>
<polygon
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[2100ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
points='60,22.1 47.5,42.9 23.9,48.3 39.8,66.5
37.7,90.7 60,81.1 82.3,90.7 80.1,66.5 96.1,48.3 72.3,43 '
/>
<polygon
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[2400ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
points='34.4,24.8 60,22.1 85.5,24.8 96.1,48.3
101.3,73.4 82.3,90.7 60,103.5 37.7,90.7 18.6,73.4 23.9,48.3 '
/>
<polygon
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[2500ms]',
)}
fill='none'
stroke='currentColor'
strokeLinejoin='round'
strokeMiterlimit='10'
points='34.4,24.8 43,7.7
60,22.1 77,7.7 85.5,24.8 104.5,27.7 96.1,48.3 115,60 101.3,73.4 104.5,92.3 82.3,90.7 77,112.3 60,103.5 43,112.3 37.7,90.7
15.5,92.3 18.6,73.4 5,60 23.9,48.3 15.5,27.7 '
/>
<line
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[2500ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
x1='60'
y1='5'
x2='60'
y2='22.1'
/>
<line
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[2500ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
x1='112.3'
y1='43'
x2='96.1'
y2='48.3'
/>
<line
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[2500ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
x1='92.3'
y1='104.5'
x2='82.3'
y2='90.7'
/>
<line
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[2500ms]',
)}
fill='none'
stroke='currentColor'
strokeMiterlimit='10'
x1='27.7'
y1='104.5'
x2='37.7'
y2='90.7'
/>
<line
className={classNames(
!reduceMotion && 'opacity-0 animate-loaderFade',
'animate-delay-[2500ms]',
)}
fill='none'
stroke='currentColor'
strokeLinejoin='round'
strokeMiterlimit='10'
x1='7.7'
y1='43'
x2='23.9'
y2='48.3'
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[5500ms]',
)}
fill='currentColor'
points='60,60 72.3,43 80.1,66.5 '
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[11000ms]',
)}
fill='currentColor'
points='60,22.1 47.5,42.9 34.4,24.8 '
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[16500ms]',
)}
fill='currentColor'
points='39.8,66.5 37.7,90.7 60,81.1 '
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[22000ms]',
)}
fill='currentColor'
points='18.6,73.4 23.9,48.3 5,60 '
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[27500ms]',
)}
fill='currentColor'
points='82.3,90.7 101.3,73.4 104.5,92.3 '
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[33000ms]',
)}
fill='currentColor'
points='96.1,48.3 104.5,27.7 112.3,43 '
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[38500ms]',
)}
fill='currentColor'
points='85.5,24.8 77,7.7 91.9,15.3 '
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[44000ms]',
)}
fill='currentColor'
points='60,103.5 82.3,90.7 60,81.1 '
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[49500ms]',
)}
fill='currentColor'
points='15.8,92.3 37.7,90.7 18.6,73.4 '
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[55000ms]',
)}
fill='currentColor'
points='15.8,27.4 34.4,24.8 23.9,48.3 '
/>
<polygon
className={classNames(
!reduceMotion && 'animate-loaderGlow',
'opacity-0 animate-delay-[60500ms]',
)}
fill='currentColor'
points='43,7.7 60,5 60,22.1 '
/>
</svg>
</div>
<Text
className={classNames(
'p-4 text-center text-white/70 w-full',
!reduceMotion && 'animate-fadein delay-4000',
)}
>
Broadcasting transaction...
</Text>
</div>
</>
)
}

View File

@ -2,9 +2,9 @@ import { Head, Html, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html className='m-0 p-0' lang='en'>
<Html className='p-0 m-0' lang='en'>
<Head />
<body className='m-0 cursor-default bg-body p-0 font-sans text-white scrollbar-hide'>
<body className='p-0 m-0 font-sans text-white cursor-default bg-body scrollbar-hide'>
<Main />
<NextScript />
</body>

View File

@ -179,6 +179,7 @@ export default function createBroadcastSlice(
return {
toast: null,
showTxLoader: false,
borrow: async (options: { accountId: string; coin: BNCoin; borrowToWallet: boolean }) => {
const borrowAction: Action = { borrow: options.coin.toCoin() }
const withdrawAction: Action = { withdraw: options.coin.toActionCoin() }
@ -200,7 +201,6 @@ export default function createBroadcastSlice(
lend: { denom: options.coin.denom, amount: 'account_balance' },
})
}
const response = await get().executeMsg({
messages: [generateExecutionMessage(get().address, ENV.ADDRESS_CREDIT_MANAGER, msg, [])],
})
@ -638,7 +638,7 @@ export default function createBroadcastSlice(
try {
const client = get().client
if (!client) return { error: 'no client detected' }
set({ showTxLoader: true })
const fee = await getEstimatedFee(options.messages)
const broadcastOptions = {
messages: options.messages,
@ -650,7 +650,7 @@ export default function createBroadcastSlice(
}
const result = await client.broadcast(broadcastOptions)
set({ showTxLoader: false })
if (result.hash) {
return { result }
}

View File

@ -83,4 +83,5 @@ interface BroadcastSlice {
borrow: BNCoin[]
reclaims: ActionCoin[]
}) => Promise<boolean>
showTxLoader: boolean
}

View File

@ -42,6 +42,8 @@ module.exports = {
fadein: 'fadein 1s ease-in-out forwards',
glow: 'glow 1000ms ease-in-out forwards',
progress: 'spin 1200ms cubic-bezier(0.5, 0, 0.5, 1) infinite',
loaderFade: 'fadein 2s ease-in-out forwards',
loaderGlow: 'vector 3s ease-in-out forwards',
},
backdropBlur: {
sticky: '50px',
@ -157,6 +159,12 @@ module.exports = {
'66%': { opacity: 1 },
'100%': { opacity: 0 },
},
vector: {
'0%': { opacity: 0 },
'33%': { opacity: 0.3 },
'66%': { opacity: 0.6 },
'100%': { opacity: 0 },
},
},
letterSpacing: {
normal: 0,
@ -391,5 +399,19 @@ module.exports = {
},
})
}),
plugin(({ matchUtilities, theme }) => {
matchUtilities(
{
'animate-delay': (value) => {
return {
'animation-delay': value,
}
},
},
{
values: theme('transitionDelay'),
},
)
}),
],
}