diff --git a/.env b/.env index bd939153..e69de29b 100644 --- a/.env +++ b/.env @@ -1,13 +0,0 @@ -# DO NOT EDIT THIS FILE WHEN USING DOCKER -# These values are used to replace the values in the built app, -# you should pass environment variables as defined in README.md - -# CONFIG # -NEXT_PUBLIC_NETWORK=mainnet - -# OSMOSIS-1 # -NEXT_PUBLIC_OSMOSIS_RPC=APP_NEXT_OSMOSIS_RPC -NEXT_PUBLIC_OSMOSIS_REST=APP_NEXT_OSMOSIS_REST - -# WALLET CONNECT # -NEXT_PUBLIC_WALLET_CONNECT_ID=APP_NEXT_WALLET_CONNECT_ID diff --git a/package.json b/package.json index 706a1a52..ae1e23ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mars-v2-frontend", - "version": "2.2.3", + "version": "2.2.4", "homepage": "./", "private": false, "license": "SEE LICENSE IN LICENSE FILE", diff --git a/src/components/Wallet/WalletConnectedButton.tsx b/src/components/Wallet/WalletConnectedButton.tsx index faf694b8..8c05a572 100644 --- a/src/components/Wallet/WalletConnectedButton.tsx +++ b/src/components/Wallet/WalletConnectedButton.tsx @@ -18,6 +18,7 @@ import chains from 'configs/chains' import { BN_ZERO } from 'constants/math' import useBaseAsset from 'hooks/assets/useBasetAsset' import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets' +import useChainConfig from 'hooks/useChainConfig' import useCurrentWallet from 'hooks/useCurrentWallet' import useICNSDomain from 'hooks/useICNSDomain' import useToggle from 'hooks/useToggle' @@ -27,7 +28,6 @@ import { NETWORK } from 'types/enums/network' import { ChainInfoID } from 'types/enums/wallet' import { truncate } from 'utils/formatters' import { getPage, getRoute } from 'utils/route' -import useChainConfig from 'hooks/useChainConfig' export default function WalletConnectedButton() { // --------------- @@ -90,7 +90,7 @@ export default function WalletConnectedButton() { }) } - navigate(getRoute(getPage(pathname), searchParams)) + navigate(getRoute(getPage(pathname), new URLSearchParams())) } useEffect(() => { diff --git a/src/components/account/Health/HealthBar.tsx b/src/components/account/Health/HealthBar.tsx index 60baafba..ecb19f10 100644 --- a/src/components/account/Health/HealthBar.tsx +++ b/src/components/account/Health/HealthBar.tsx @@ -63,16 +63,22 @@ export default function HealthBar({ health={isUpdated ? updatedHealth : health} healthFactor={isUpdated ? updatedHealthFactor : healthFactor} > - <> +
{showIcon && ( )} -
+
- +
) } diff --git a/src/components/account/Health/HealthIcon.tsx b/src/components/account/Health/HealthIcon.tsx index 858cb0bf..43891b01 100644 --- a/src/components/account/Health/HealthIcon.tsx +++ b/src/components/account/Health/HealthIcon.tsx @@ -5,7 +5,7 @@ import { ExclamationMarkCircled, Heart } from 'components/common/Icons' interface Props { isLoading: boolean health: number - className: string + className?: string colorClass?: string } @@ -14,9 +14,9 @@ export default function HealthIcon(props: Props) { const color = colorClass ?? 'text-white' return ( - <> +
{!isLoading && health === 0 ? ( - + ) : ( )} - +
) } diff --git a/src/components/borrow/BorrowActionButtons.tsx b/src/components/borrow/BorrowActionButtons.tsx deleted file mode 100644 index 5d766d0c..00000000 --- a/src/components/borrow/BorrowActionButtons.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useCallback } from 'react' - -import Button from 'components/common/Button' -import ActionButton from 'components/common/Button/ActionButton' -import { HandCoins, Plus } from 'components/common/Icons' -import useMarketEnabledAssets from 'hooks/assets/useMarketEnabledAssets' -import useStore from 'store' - -interface Props { - data: BorrowMarketTableData -} - -export default function BorrowActionButtons(props: Props) { - const { asset, accountDebt } = props.data - const marketAssets = useMarketEnabledAssets() - const currentAsset = marketAssets.find((a) => a.denom === asset.denom) - - const borrowHandler = useCallback(() => { - if (!currentAsset) return null - useStore.setState({ borrowModal: { asset: currentAsset, marketData: props.data } }) - }, [currentAsset, props.data]) - - const repayHandler = useCallback(() => { - if (!currentAsset) return null - useStore.setState({ - borrowModal: { asset: currentAsset, marketData: props.data, isRepay: true }, - }) - }, [currentAsset, props.data]) - - return ( -
- } - onClick={borrowHandler} - color='secondary' - text={accountDebt ? 'Borrow more' : 'Borrow'} - className='text-center min-w-40' - /> - {accountDebt && ( -
- ) -} diff --git a/src/components/borrow/Table/AvailableBorrowingsTable.tsx b/src/components/borrow/Table/AvailableBorrowingsTable.tsx index 652baaeb..b025e004 100644 --- a/src/components/borrow/Table/AvailableBorrowingsTable.tsx +++ b/src/components/borrow/Table/AvailableBorrowingsTable.tsx @@ -2,12 +2,10 @@ import { Row } from '@tanstack/react-table' import { Table as TanstackTable } from '@tanstack/table-core/build/lib/types' import { useCallback } from 'react' -import BorrowActionButtons from 'components/borrow/BorrowActionButtons' import { NAME_META } from 'components/borrow/Table/Columns/Name' import useAvailableColumns from 'components/borrow/Table/Columns/useAvailableColumns' import MarketDetails from 'components/common/MarketDetails' import Table from 'components/common/Table' -import ActionButtonRow from 'components/common/Table/ActionButtonRow' type Props = { data: BorrowMarketTableData[] @@ -20,14 +18,7 @@ export default function AvailableBorrowingsTable(props: Props) { const renderExpanded = useCallback( (row: Row, _: TanstackTable) => { const currentRow = row as Row - return ( - <> - - - - - - ) + return }, [], ) diff --git a/src/components/borrow/Table/Columns/BorrowButton.tsx b/src/components/borrow/Table/Columns/BorrowButton.tsx new file mode 100644 index 00000000..421a277d --- /dev/null +++ b/src/components/borrow/Table/Columns/BorrowButton.tsx @@ -0,0 +1,61 @@ +import { useCallback } from 'react' + +import ActionButton from 'components/common/Button/ActionButton' +import { Plus } from 'components/common/Icons' +import Text from 'components/common/Text' +import { Tooltip } from 'components/common/Tooltip' +import ConditionalWrapper from 'hocs/ConditionalWrapper' +import useCurrentAccount from 'hooks/accounts/useCurrentAccount' +import useStore from 'store' + +export const BORROW_BUTTON_META = { + accessorKey: 'borrow', + enableSorting: false, + header: '', +} + +interface Props { + data: LendingMarketTableData +} +export default function BorrowButton(props: Props) { + const account = useCurrentAccount() + const address = useStore((s) => s.address) + const hasNoDeposits = !account?.deposits?.length && !account?.lends?.length && !!address + + const borrowHandler = useCallback(() => { + if (!props.data.asset) return null + useStore.setState({ borrowModal: { asset: props.data.asset, marketData: props.data } }) + }, [props.data]) + + return ( +
+ ( + {`You don’t have any collateral. + Please first deposit into your Credit Account before borrowing.`} + } + contentClassName='max-w-[200px]' + className='ml-auto' + > + {children} + + )} + > + } + disabled={hasNoDeposits} + color='tertiary' + onClick={(e) => { + borrowHandler() + e.stopPropagation() + }} + text='Borrow' + /> + +
+ ) +} diff --git a/src/components/borrow/Table/Columns/BorrowRate.tsx b/src/components/borrow/Table/Columns/BorrowRate.tsx index 01c154ab..2f8cef90 100644 --- a/src/components/borrow/Table/Columns/BorrowRate.tsx +++ b/src/components/borrow/Table/Columns/BorrowRate.tsx @@ -4,7 +4,6 @@ import Loading from 'components/common/Loading' export const BORROW_RATE_META = { accessorKey: 'apy.borrow', header: 'Borrow Rate APY', - meta: { className: 'w-40' }, } interface Props { diff --git a/src/components/borrow/Table/Columns/Chevron.tsx b/src/components/borrow/Table/Columns/Chevron.tsx new file mode 100644 index 00000000..efd9d678 --- /dev/null +++ b/src/components/borrow/Table/Columns/Chevron.tsx @@ -0,0 +1,21 @@ +import { ChevronDown, ChevronUp } from 'components/common/Icons' + +export const CHEVRON_META = { + id: 'chevron', + enableSorting: false, + header: '', + meta: { + className: 'w-5', + }, +} + +interface Props { + isExpanded: boolean +} +export default function Chevron(props: Props) { + return ( +
+
{props.isExpanded ? : }
+
+ ) +} diff --git a/src/components/borrow/Table/Columns/Liquidity.tsx b/src/components/borrow/Table/Columns/Liquidity.tsx index c2202edc..1a871f3e 100644 --- a/src/components/borrow/Table/Columns/Liquidity.tsx +++ b/src/components/borrow/Table/Columns/Liquidity.tsx @@ -10,7 +10,6 @@ export const LIQUIDITY_META = { accessorKey: 'liquidity', header: 'Liquidity Available', id: 'liquidity', - meta: { className: 'w-40' }, } export const liquiditySortingFn = ( diff --git a/src/components/borrow/Table/Columns/Manage.tsx b/src/components/borrow/Table/Columns/Manage.tsx index f6515b14..c7112d06 100644 --- a/src/components/borrow/Table/Columns/Manage.tsx +++ b/src/components/borrow/Table/Columns/Manage.tsx @@ -1,20 +1,55 @@ -import { ChevronDown, ChevronUp } from 'components/common/Icons' +import { useCallback, useMemo } from 'react' + +import DropDownButton from 'components/common/Button/DropDownButton' +import { HandCoins, Plus } from 'components/common/Icons' +import useStore from 'store' export const MANAGE_META = { accessorKey: 'manage', enableSorting: false, - header: 'Manage', - meta: { className: 'w-30' }, + header: '', } interface Props { - isExpanded: boolean + data: BorrowMarketTableData } export default function Manage(props: Props) { + const address = useStore((s) => s.address) + + const borrowHandler = useCallback(() => { + if (!props.data.asset) return null + useStore.setState({ borrowModal: { asset: props.data.asset, marketData: props.data } }) + }, [props.data]) + + const repayHandler = useCallback(() => { + if (!props.data.asset) return null + useStore.setState({ + borrowModal: { asset: props.data.asset, marketData: props.data, isRepay: true }, + }) + }, [props.data]) + + const ITEMS: DropDownItem[] = useMemo( + () => [ + { + icon: , + text: 'Borrow more', + onClick: borrowHandler, + }, + { + icon: , + text: 'Repay', + onClick: repayHandler, + }, + ], + [borrowHandler, repayHandler], + ) + + if (!address) return null + return ( -
-
{props.isExpanded ? : }
+
+
) } diff --git a/src/components/borrow/Table/Columns/useAvailableColumns.tsx b/src/components/borrow/Table/Columns/useAvailableColumns.tsx index 16eb04d1..9cc2bd8e 100644 --- a/src/components/borrow/Table/Columns/useAvailableColumns.tsx +++ b/src/components/borrow/Table/Columns/useAvailableColumns.tsx @@ -1,12 +1,13 @@ import { ColumnDef } from '@tanstack/react-table' import { useMemo } from 'react' +import BorrowButton, { BORROW_BUTTON_META } from 'components/borrow/Table/Columns/BorrowButton' import BorrowRate, { BORROW_RATE_META } from 'components/borrow/Table/Columns/BorrowRate' +import Chevron, { CHEVRON_META } from 'components/borrow/Table/Columns/Chevron' import Liquidity, { LIQUIDITY_META, liquiditySortingFn, } from 'components/borrow/Table/Columns/Liquidity' -import Manage, { MANAGE_META } from 'components/borrow/Table/Columns/Manage' import Name, { NAME_META } from 'components/borrow/Table/Columns/Name' export default function useAvailableColumns() { @@ -26,8 +27,12 @@ export default function useAvailableColumns() { sortingFn: liquiditySortingFn, }, { - ...MANAGE_META, - cell: ({ row }) => , + ...BORROW_BUTTON_META, + cell: ({ row }) => , + }, + { + ...CHEVRON_META, + cell: ({ row }) => , }, ] }, []) diff --git a/src/components/borrow/Table/Columns/useDepositedColumns.tsx b/src/components/borrow/Table/Columns/useDepositedColumns.tsx index fa657241..4c311786 100644 --- a/src/components/borrow/Table/Columns/useDepositedColumns.tsx +++ b/src/components/borrow/Table/Columns/useDepositedColumns.tsx @@ -2,6 +2,7 @@ import { ColumnDef } from '@tanstack/react-table' import { useMemo } from 'react' import BorrowRate, { BORROW_RATE_META } from 'components/borrow/Table/Columns/BorrowRate' +import Chevron, { CHEVRON_META } from 'components/borrow/Table/Columns/Chevron' import Debt, { DEBT_META, debtSortingFn } from 'components/borrow/Table/Columns/Debt' import Liquidity, { LIQUIDITY_META, @@ -33,7 +34,11 @@ export default function useDepositedColumns() { }, { ...MANAGE_META, - cell: ({ row }) => , + cell: ({ row }) => , + }, + { + ...CHEVRON_META, + cell: ({ row }) => , }, ] }, []) diff --git a/src/components/borrow/Table/DepositedBorrowingsTable.tsx b/src/components/borrow/Table/DepositedBorrowingsTable.tsx index 85b6fa96..8eaf08da 100644 --- a/src/components/borrow/Table/DepositedBorrowingsTable.tsx +++ b/src/components/borrow/Table/DepositedBorrowingsTable.tsx @@ -1,12 +1,10 @@ import { Row } from '@tanstack/react-table' import { useCallback } from 'react' -import BorrowActionButtons from 'components/borrow/BorrowActionButtons' import { NAME_META } from 'components/borrow/Table/Columns/Name' import useDepositedColumns from 'components/borrow/Table/Columns/useDepositedColumns' import MarketDetails from 'components/common/MarketDetails' import Table from 'components/common/Table' -import ActionButtonRow from 'components/common/Table/ActionButtonRow' type Props = { data: BorrowMarketTableData[] @@ -17,15 +15,7 @@ export default function DepositedBorrowingsTable(props: Props) { const columns = useDepositedColumns() const renderExpanded = useCallback((row: Row) => { - const currentRow = row as Row - return ( - <> - - - - - - ) + return }, []) if (!props.data.length) return null diff --git a/src/components/common/Button/DropDownButton.tsx b/src/components/common/Button/DropDownButton.tsx index 6b54572e..afc754c7 100644 --- a/src/components/common/Button/DropDownButton.tsx +++ b/src/components/common/Button/DropDownButton.tsx @@ -1,12 +1,16 @@ +import classNames from 'classnames' + import Button from 'components/common/Button/index' import { ChevronDown } from 'components/common/Icons' import Text from 'components/common/Text' import { Tooltip } from 'components/common/Tooltip' +import ConditionalWrapper from 'hocs/ConditionalWrapper' import useToggle from 'hooks/useToggle' interface Props extends ButtonProps { items: DropDownItem[] text: string + showProgressIndicator?: boolean } export default function DropDownButton(props: Props) { @@ -16,16 +20,20 @@ export default function DropDownButton(props: Props) { content={ toggleIsOpen(false)} {...props} />} type='info' placement='bottom' - contentClassName='!bg-white/10 backdrop-blur-xl !p-0' + contentClassName='!bg-white/10 backdrop-blur-xl !p-0 w-full min-w-[140px]' interactive hideArrow visible={isOpen} onClickOutside={() => toggleIsOpen(false)} > + + ) } diff --git a/src/components/common/DepositCapMessage.tsx b/src/components/common/DepositCapMessage.tsx index 1182e5f8..9b6be7c5 100644 --- a/src/components/common/DepositCapMessage.tsx +++ b/src/components/common/DepositCapMessage.tsx @@ -18,7 +18,11 @@ export default function DepositCapMessage(props: Props) { return (
- {props.showIcon && } + {props.showIcon && ( +
+ +
+ )}
Deposit Cap Reached! {`Unfortunately you're not able to ${ diff --git a/src/components/common/Table/Row.tsx b/src/components/common/Table/Row.tsx index bdc4fa53..eb45dfb9 100644 --- a/src/components/common/Table/Row.tsx +++ b/src/components/common/Table/Row.tsx @@ -10,6 +10,7 @@ interface Props { className?: string isSelectable?: boolean type?: TableType + onClick?: (id: string) => void } function getBorderColor( @@ -36,7 +37,7 @@ export default function Row(props: Props) { key={`${row.id}-row`} className={classNames( 'group/row transition-bg', - (renderExpanded || isSelectable) && 'hover:cursor-pointer', + (renderExpanded || isSelectable || props.onClick) && 'hover:cursor-pointer', canExpand && row.getIsExpanded() ? 'is-expanded bg-black/20' : 'hover:bg-white/5', )} onClick={(e) => { @@ -49,6 +50,10 @@ export default function Row(props: Props) { table.resetExpanded() !isExpanded && row.toggleExpanded() } + + if (props.onClick) { + props.onClick((row.original as any).asset.denom) + } }} > {row.getVisibleCells().map((cell) => { @@ -61,7 +66,7 @@ export default function Row(props: Props) { spacingClassName ?? 'px-3 py-4', type && type !== 'strategies' && isSymbolOrName && 'border-l', type && type !== 'strategies' && getBorderColor(type, cell.row.original as any), - cell.column.columnDef.meta?.className, + cell.column.columnDef.meta?.className ?? 'w-min', )} > {flexRender(cell.column.columnDef.cell, cell.getContext())} diff --git a/src/components/common/Table/index.tsx b/src/components/common/Table/index.tsx index 3bfad776..ce9ca248 100644 --- a/src/components/common/Table/index.tsx +++ b/src/components/common/Table/index.tsx @@ -31,6 +31,7 @@ interface Props { hideCard?: boolean setRowSelection?: OnChangeFn selectedRows?: RowSelectionState + onClickRow?: (id: string) => void } export default function Table(props: Props) { @@ -75,6 +76,7 @@ export default function Table(props: Props) { props.spacingClassName ?? 'px-4 py-3', header.column.getCanSort() && 'hover:cursor-pointer', header.id === 'symbol' || header.id === 'name' ? 'text-left' : 'text-right', + 'w-min', header.column.columnDef.meta?.className, )} > @@ -122,6 +124,7 @@ export default function Table(props: Props) { spacingClassName={props.spacingClassName} isSelectable={!!props.setRowSelection} type={props.type} + onClick={props.onClickRow} /> ))} diff --git a/src/components/common/Tooltip/TooltipContent.tsx b/src/components/common/Tooltip/TooltipContent.tsx index f351409b..eb00b4bd 100644 --- a/src/components/common/Tooltip/TooltipContent.tsx +++ b/src/components/common/Tooltip/TooltipContent.tsx @@ -16,9 +16,9 @@ export default function TooltipContent(props: Props) {
{ visible={props.visible} > {props.children ? ( - { )} > {props.children} - +
) : ( { const { vault } = props @@ -26,7 +29,12 @@ export const Deposit = (props: Props) => { return (
- + } + />
) } diff --git a/src/components/earn/farm/Table/Columns/Details.tsx b/src/components/earn/farm/Table/Columns/Details.tsx deleted file mode 100644 index 644a6058..00000000 --- a/src/components/earn/farm/Table/Columns/Details.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import classNames from 'classnames' -import React from 'react' - -import { ChevronDown } from 'components/common/Icons' -import Loading from 'components/common/Loading' - -export const DETAILS_META = { accessorKey: 'details', enableSorting: false, header: 'Deposit' } - -interface Props { - isLoading: boolean - isExpanded: boolean -} - -export default function Details(props: Props) { - if (props.isLoading) return - - return ( -
-
- -
-
- ) -} diff --git a/src/components/earn/farm/Table/Columns/Manage.tsx b/src/components/earn/farm/Table/Columns/Manage.tsx new file mode 100644 index 00000000..ab85bebc --- /dev/null +++ b/src/components/earn/farm/Table/Columns/Manage.tsx @@ -0,0 +1,116 @@ +import moment from 'moment/moment' +import React, { useCallback, useMemo, useState } from 'react' + +import { AccountArrowDown, LockLocked, LockUnlocked, Plus } from 'components/common/Icons' +import Loading from 'components/common/Loading' +import { VaultStatus } from 'types/enums/vault' + +import { DEFAULT_SETTINGS } from '../../../../../constants/defaultSettings' +import { LocalStorageKeys } from '../../../../../constants/localStorageKeys' +import useLocalStorage from '../../../../../hooks/localStorage/useLocalStorage' +import useAccountId from '../../../../../hooks/useAccountId' +import useStore from '../../../../../store' +import DropDownButton from '../../../../common/Button/DropDownButton' + +export const MANAGE_META = { accessorKey: 'details', enableSorting: false, header: '' } + +interface Props { + vault: DepositedVault + isLoading: boolean + isExpanded: boolean +} + +export default function Manage(props: Props) { + const accountId = useAccountId() + const address = useStore((s) => s.address) + const withdrawFromVaults = useStore((s) => s.withdrawFromVaults) + const [slippage] = useLocalStorage(LocalStorageKeys.SLIPPAGE, DEFAULT_SETTINGS.slippage) + const [isConfirming, setIsConfirming] = useState(false) + + const depositMoreHandler = useCallback(() => { + useStore.setState({ + vaultModal: { + vault: props.vault, + isDeposited: true, + selectedBorrowDenoms: [props.vault.denoms.secondary], + isCreate: false, + }, + }) + }, [props.vault]) + + const unlockHandler = useCallback( + () => useStore.setState({ unlockModal: { vault: props.vault } }), + [props.vault], + ) + + const withdrawHandler = useCallback(async () => { + if (!accountId) return + setIsConfirming(true) + await withdrawFromVaults({ + accountId: accountId, + vaults: [props.vault], + slippage, + }) + }, [accountId, props.vault, slippage, withdrawFromVaults]) + + const ITEMS: DropDownItem[] = useMemo( + () => [ + { + icon: , + text: 'Deposit more', + onClick: depositMoreHandler, + }, + ...(props.vault.status === VaultStatus.ACTIVE + ? [ + { + icon: , + text: 'Unlock to withdraw', + onClick: unlockHandler, + }, + ] + : []), + ...(props.vault.status === VaultStatus.UNLOCKING + ? [ + { + icon: , + text: `Withdraw in ${moment(props.vault?.unlocksAt).fromNow(true)}`, + onClick: () => {}, + disabled: true, + disabledTooltip: '', + }, + ] + : []), + ...(props.vault.status === VaultStatus.UNLOCKED + ? [ + { + icon: , + text: 'Withdraw funds', + onClick: withdrawHandler, + }, + ] + : []), + ], + [ + depositMoreHandler, + props.vault.status, + props.vault?.unlocksAt, + unlockHandler, + withdrawHandler, + ], + ) + + if (props.isLoading) return + + if (!address) return null + + return ( +
+ +
+ ) +} diff --git a/src/components/earn/farm/Table/Columns/useAvailableColumns.tsx b/src/components/earn/farm/Table/Columns/useAvailableColumns.tsx index 7b155b2c..8269d7d1 100644 --- a/src/components/earn/farm/Table/Columns/useAvailableColumns.tsx +++ b/src/components/earn/farm/Table/Columns/useAvailableColumns.tsx @@ -2,7 +2,6 @@ import { ColumnDef } from '@tanstack/react-table' import { useMemo } from 'react' import Apy, { APY_META } from 'components/earn/farm/Table/Columns/Apy' -import { Deposit } from 'components/earn/farm/Table/Columns/Deposit' import DepositCap, { DEPOSIT_CAP_META, depositCapSortingFn, @@ -10,7 +9,8 @@ import DepositCap, { import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV' import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name' import TVL, { TVL_META } from 'components/earn/farm/Table/Columns/TVL' -import { DETAILS_META } from 'components/earn/farm/Table/Columns/Details' + +import { Deposit, DEPOSIT_META } from './Deposit' interface Props { isLoading: boolean @@ -41,7 +41,7 @@ export default function useAvailableColumns(props: Props) { cell: ({ row }) => , }, { - ...DETAILS_META, + ...DEPOSIT_META, cell: ({ row }) => , }, ] diff --git a/src/components/earn/farm/Table/Columns/useDepositedColumns.tsx b/src/components/earn/farm/Table/Columns/useDepositedColumns.tsx index 56e62b91..80da2f0b 100644 --- a/src/components/earn/farm/Table/Columns/useDepositedColumns.tsx +++ b/src/components/earn/farm/Table/Columns/useDepositedColumns.tsx @@ -6,7 +6,7 @@ import DepositCap, { DEPOSIT_CAP_META, depositCapSortingFn, } from 'components/earn/farm/Table/Columns/DepositCap' -import Details, { DETAILS_META } from 'components/earn/farm/Table/Columns/Details' +import Manage, { MANAGE_META } from 'components/earn/farm/Table/Columns/Manage' import MaxLTV, { LTV_MAX_META } from 'components/earn/farm/Table/Columns/MaxLTV' import Name, { NAME_META } from 'components/earn/farm/Table/Columns/Name' import PositionValue, { @@ -55,8 +55,14 @@ export default function useDepositedColumns(props: Props) { ), }, { - ...DETAILS_META, - cell: ({ row }) =>
, + ...MANAGE_META, + cell: ({ row }) => ( + + ), }, ] }, [props.isLoading]) diff --git a/src/components/earn/farm/Table/DepositedVaultsTable.tsx b/src/components/earn/farm/Table/DepositedVaultsTable.tsx index 3b7caeef..208b4a1f 100644 --- a/src/components/earn/farm/Table/DepositedVaultsTable.tsx +++ b/src/components/earn/farm/Table/DepositedVaultsTable.tsx @@ -1,10 +1,7 @@ -import { Row } from '@tanstack/react-table' -import { Table as TanStackTable } from '@tanstack/table-core/build/lib/types' -import React, { useCallback } from 'react' +import React from 'react' -import useDepositedColumns from 'components/earn/farm/Table/Columns/useDepositedColumns' -import VaultExpanded from 'components/earn/farm/VaultExpanded' import Table from 'components/common/Table' +import useDepositedColumns from 'components/earn/farm/Table/Columns/useDepositedColumns' type Props = { data: DepositedVault[] @@ -14,20 +11,12 @@ type Props = { export default function DepositedVaultsTable(props: Props) { const columns = useDepositedColumns({ isLoading: props.isLoading }) - const renderExpanded = useCallback( - (row: Row, table: TanStackTable) => ( - - ), - [], - ) - return ( ) } diff --git a/src/components/earn/lend/LendingActionButtons.tsx b/src/components/earn/lend/LendingActionButtons.tsx deleted file mode 100644 index 99923f0a..00000000 --- a/src/components/earn/lend/LendingActionButtons.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { useCallback } from 'react' - -import { ACCOUNT_MENU_BUTTON_ID } from 'components/account/AccountMenuContent' -import Button from 'components/common/Button' -import ActionButton from 'components/common/Button/ActionButton' -import { ArrowDownLine, ArrowUpLine, Enter, ExclamationMarkCircled } from 'components/common/Icons' -import Text from 'components/common/Text' -import { Tooltip } from 'components/common/Tooltip' -import ConditionalWrapper from 'hocs/ConditionalWrapper' -import useAccountId from 'hooks/useAccountId' -import useAlertDialog from 'hooks/useAlertDialog' -import useAutoLend from 'hooks/useAutoLend' -import useCurrentAccountDeposits from 'hooks/useCurrentAccountDeposits' -import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal' -import useStore from 'store' -import { byDenom } from 'utils/array' - -interface Props { - data: LendingMarketTableData -} - -const buttonClassnames = 'm-0 flex w-40' -const iconClassnames = 'ml-0 mr-1 w-4 h-4' - -export default function LendingActionButtons(props: Props) { - const { asset, accountLentValue: accountLendValue } = props.data - const accountDeposits = useCurrentAccountDeposits() - const { openLend, openReclaim } = useLendAndReclaimModal() - const { open: showAlertDialog } = useAlertDialog() - const { isAutoLendEnabledForCurrentAccount } = useAutoLend() - const assetDepositAmount = accountDeposits.find(byDenom(asset.denom))?.amount - const address = useStore((s) => s.address) - const accountId = useAccountId() - const hasNoDeposit = !!(!assetDepositAmount && address && accountId) - - const handleUnlend = useCallback(() => { - if (isAutoLendEnabledForCurrentAccount) { - showAlertDialog({ - icon: , - title: 'Disable Automatically Lend Assets', - content: - "Your auto-lend feature is currently enabled. To unlend your funds, please confirm if you'd like to disable this feature in order to continue.", - positiveButton: { - onClick: () => document.getElementById(ACCOUNT_MENU_BUTTON_ID)?.click(), - text: 'Continue to Account Settings', - icon: , - }, - negativeButton: { - text: 'Cancel', - }, - }) - - return - } - - openReclaim(props.data) - }, [isAutoLendEnabledForCurrentAccount, openReclaim, props.data, showAlertDialog]) - - return ( -
- {accountLendValue && accountLendValue.isGreaterThan(0) && ( - - )} - - ( - {`You don’t have any ${asset.symbol}. Please first deposit ${asset.symbol} into your Credit Account before lending.`} - } - > - {children} - - )} - > - } - iconClassName={iconClassnames} - disabled={hasNoDeposit} - color='secondary' - onClick={() => openLend(props.data)} - className={buttonClassnames} - text='Lend' - /> - -
- ) -} diff --git a/src/components/earn/lend/Table/AvailableLendsTable.tsx b/src/components/earn/lend/Table/AvailableLendsTable.tsx index a8b10b5b..e4da0208 100644 --- a/src/components/earn/lend/Table/AvailableLendsTable.tsx +++ b/src/components/earn/lend/Table/AvailableLendsTable.tsx @@ -1,12 +1,10 @@ import { Row } from '@tanstack/react-table' import { useCallback } from 'react' -import LendingActionButtons from 'components/earn/lend/LendingActionButtons' -import { NAME_META } from 'components/earn/lend/Table/Columns/Name' -import useAvailableColumns from 'components/earn/lend/Table/Columns/useAvailableColumns' import MarketDetails from 'components/common/MarketDetails' import Table from 'components/common/Table' -import ActionButtonRow from 'components/common/Table/ActionButtonRow' +import { NAME_META } from 'components/earn/lend/Table/Columns/Name' +import useAvailableColumns from 'components/earn/lend/Table/Columns/useAvailableColumns' type Props = { data: LendingMarketTableData[] @@ -19,9 +17,6 @@ export default function AvailableLendsTable(props: Props) { const renderExpanded = useCallback( (row: Row) => ( <> - - - ), diff --git a/src/components/earn/lend/Table/Columns/Chevron.tsx b/src/components/earn/lend/Table/Columns/Chevron.tsx new file mode 100644 index 00000000..efd9d678 --- /dev/null +++ b/src/components/earn/lend/Table/Columns/Chevron.tsx @@ -0,0 +1,21 @@ +import { ChevronDown, ChevronUp } from 'components/common/Icons' + +export const CHEVRON_META = { + id: 'chevron', + enableSorting: false, + header: '', + meta: { + className: 'w-5', + }, +} + +interface Props { + isExpanded: boolean +} +export default function Chevron(props: Props) { + return ( +
+
{props.isExpanded ? : }
+
+ ) +} diff --git a/src/components/earn/lend/Table/Columns/DepositCap.tsx b/src/components/earn/lend/Table/Columns/DepositCap.tsx index efd92d05..1ad1028e 100644 --- a/src/components/earn/lend/Table/Columns/DepositCap.tsx +++ b/src/components/earn/lend/Table/Columns/DepositCap.tsx @@ -10,7 +10,6 @@ export const DEPOSIT_CAP_META = { accessorKey: 'marketDepositCap', header: 'Deposit Cap', id: 'marketDepositCap', - meta: { className: 'w-40' }, } export const marketDepositCapSortingFn = ( diff --git a/src/components/earn/lend/Table/Columns/LendButton.tsx b/src/components/earn/lend/Table/Columns/LendButton.tsx new file mode 100644 index 00000000..ffe78a75 --- /dev/null +++ b/src/components/earn/lend/Table/Columns/LendButton.tsx @@ -0,0 +1,60 @@ +import ActionButton from 'components/common/Button/ActionButton' +import { ArrowUpLine } from 'components/common/Icons' +import Text from 'components/common/Text' +import { Tooltip } from 'components/common/Tooltip' +import ConditionalWrapper from 'hocs/ConditionalWrapper' +import useAccountId from 'hooks/useAccountId' +import useCurrentAccountDeposits from 'hooks/useCurrentAccountDeposits' +import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal' +import useStore from 'store' +import { byDenom } from 'utils/array' + +export const LEND_BUTTON_META = { + accessorKey: 'lend', + enableSorting: false, + header: '', +} + +interface Props { + data: LendingMarketTableData +} +export default function LendButton(props: Props) { + const { openLend } = useLendAndReclaimModal() + const accountDeposits = useCurrentAccountDeposits() + const assetDepositAmount = accountDeposits.find(byDenom(props.data.asset.denom))?.amount + const address = useStore((s) => s.address) + const accountId = useAccountId() + const hasNoDeposit = !!(!assetDepositAmount && address && accountId) + + return ( +
+ ( + {`You don’t have any ${props.data.asset.symbol}. + Please first deposit ${props.data.asset.symbol} into your Credit Account before lending.`} + } + contentClassName='max-w-[200px]' + className='ml-auto' + > + {children} + + )} + > + } + disabled={hasNoDeposit} + color='tertiary' + onClick={(e) => { + openLend(props.data) + e.stopPropagation() + }} + text='Lend' + /> + +
+ ) +} diff --git a/src/components/earn/lend/Table/Columns/Manage.tsx b/src/components/earn/lend/Table/Columns/Manage.tsx index 863c2084..4f031e9f 100644 --- a/src/components/earn/lend/Table/Columns/Manage.tsx +++ b/src/components/earn/lend/Table/Columns/Manage.tsx @@ -1,21 +1,82 @@ -import { ChevronDown, ChevronUp } from 'components/common/Icons' +import { useCallback, useMemo } from 'react' + +import { ACCOUNT_MENU_BUTTON_ID } from 'components/account/AccountMenuContent' +import DropDownButton from 'components/common/Button/DropDownButton' +import { ArrowDownLine, ArrowUpLine, Enter, ExclamationMarkCircled } from 'components/common/Icons' +import useCurrentAccount from 'hooks/accounts/useCurrentAccount' +import useAlertDialog from 'hooks/useAlertDialog' +import useAutoLend from 'hooks/useAutoLend' +import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal' +import useStore from 'store' export const MANAGE_META = { accessorKey: 'manage', enableSorting: false, - header: 'Manage', - meta: { - className: 'w-30', - }, + header: '', } interface Props { - isExpanded: boolean + data: LendingMarketTableData } export default function Manage(props: Props) { + const { openLend, openReclaim } = useLendAndReclaimModal() + const { isAutoLendEnabledForCurrentAccount } = useAutoLend() + const { open: showAlertDialog } = useAlertDialog() + const address = useStore((s) => s.address) + const account = useCurrentAccount() + + const hasAssetInDeposits = useMemo( + () => !!account?.deposits?.find((deposit) => deposit.denom === props.data.asset.denom), + [account?.deposits, props.data.asset.denom], + ) + + const handleUnlend = useCallback(() => { + if (isAutoLendEnabledForCurrentAccount) { + showAlertDialog({ + icon: , + title: 'Disable Automatically Lend Assets', + content: + "Your auto-lend feature is currently enabled. To unlend your funds, please confirm if you'd like to disable this feature in order to continue.", + positiveButton: { + onClick: () => document.getElementById(ACCOUNT_MENU_BUTTON_ID)?.click(), + text: 'Continue to Account Settings', + icon: , + }, + negativeButton: { + text: 'Cancel', + }, + }) + + return + } + + openReclaim(props.data) + }, [isAutoLendEnabledForCurrentAccount, openReclaim, props.data, showAlertDialog]) + + const ITEMS: DropDownItem[] = useMemo( + () => [ + { + icon: , + text: 'Lend more', + onClick: () => openLend(props.data), + disabled: !hasAssetInDeposits, + disabledTooltip: `You don’t have any ${props.data.asset.symbol}. + Please first deposit ${props.data.asset.symbol} into your Credit Account before lending.`, + }, + { + icon: , + text: 'Unlend', + onClick: handleUnlend, + }, + ], + [handleUnlend, hasAssetInDeposits, openLend, props.data], + ) + + if (!address) return null + return ( -
-
{props.isExpanded ? : }
+
+
) } diff --git a/src/components/earn/lend/Table/Columns/useAvailableColumns.tsx b/src/components/earn/lend/Table/Columns/useAvailableColumns.tsx index c066a1a7..976402c1 100644 --- a/src/components/earn/lend/Table/Columns/useAvailableColumns.tsx +++ b/src/components/earn/lend/Table/Columns/useAvailableColumns.tsx @@ -2,11 +2,12 @@ import { ColumnDef } from '@tanstack/react-table' import { useMemo } from 'react' import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy' +import Chevron, { CHEVRON_META } from 'components/earn/lend/Table/Columns/Chevron' import DepositCap, { DEPOSIT_CAP_META, marketDepositCapSortingFn, } from 'components/earn/lend/Table/Columns/DepositCap' -import Manage, { MANAGE_META } from 'components/earn/lend/Table/Columns/Manage' +import LendButton, { LEND_BUTTON_META } from 'components/earn/lend/Table/Columns/LendButton' import Name, { NAME_META } from 'components/earn/lend/Table/Columns/Name' interface Props { @@ -36,8 +37,12 @@ export default function useAvailableColumns(props: Props) { sortingFn: marketDepositCapSortingFn, }, { - ...MANAGE_META, - cell: ({ row }) => , + ...LEND_BUTTON_META, + cell: ({ row }) => , + }, + { + ...CHEVRON_META, + cell: ({ row }) => , }, ] }, [props.isLoading]) diff --git a/src/components/earn/lend/Table/Columns/useDepositedColumns.tsx b/src/components/earn/lend/Table/Columns/useDepositedColumns.tsx index 6274f09e..d39702fe 100644 --- a/src/components/earn/lend/Table/Columns/useDepositedColumns.tsx +++ b/src/components/earn/lend/Table/Columns/useDepositedColumns.tsx @@ -2,6 +2,7 @@ import { ColumnDef } from '@tanstack/react-table' import { useMemo } from 'react' import Apy, { APY_META } from 'components/earn/lend/Table/Columns/Apy' +import Chevron, { CHEVRON_META } from 'components/earn/lend/Table/Columns/Chevron' import DepositCap, { DEPOSIT_CAP_META, marketDepositCapSortingFn, @@ -48,7 +49,11 @@ export default function useDepositedColumns(props: Props) { }, { ...MANAGE_META, - cell: ({ row }) => , + cell: ({ row }) => , + }, + { + ...CHEVRON_META, + cell: ({ row }) => , }, ] }, [props.isLoading]) diff --git a/src/components/earn/lend/Table/DepositedLendsTable.tsx b/src/components/earn/lend/Table/DepositedLendsTable.tsx index 42d37ade..b63da489 100644 --- a/src/components/earn/lend/Table/DepositedLendsTable.tsx +++ b/src/components/earn/lend/Table/DepositedLendsTable.tsx @@ -1,12 +1,10 @@ import { Row } from '@tanstack/react-table' import { useCallback } from 'react' -import LendingActionButtons from 'components/earn/lend/LendingActionButtons' -import { NAME_META } from 'components/earn/lend/Table/Columns/Name' -import useDepositedColumns from 'components/earn/lend/Table/Columns/useDepositedColumns' import MarketDetails from 'components/common/MarketDetails' import Table from 'components/common/Table' -import ActionButtonRow from 'components/common/Table/ActionButtonRow' +import { NAME_META } from 'components/earn/lend/Table/Columns/Name' +import useDepositedColumns from 'components/earn/lend/Table/Columns/useDepositedColumns' type Props = { data: LendingMarketTableData[] @@ -17,14 +15,7 @@ export default function DepositedLendsTable(props: Props) { const columns = useDepositedColumns({ isLoading: props.isLoading }) const renderExpanded = useCallback( - (row: Row) => ( - <> - - - - - - ), + (row: Row) => , [], ) diff --git a/src/components/perps/BalancesTable/index.tsx b/src/components/perps/BalancesTable/index.tsx index 6e643172..94b7774b 100644 --- a/src/components/perps/BalancesTable/index.tsx +++ b/src/components/perps/BalancesTable/index.tsx @@ -1,10 +1,32 @@ +import { useCallback } from 'react' +import { useSearchParams } from 'react-router-dom' + +import Table from 'components/common/Table' import usePerpsBalancesColumns from 'components/perps/BalancesTable/Columns/usePerpsBalancesColumns' import usePerpsBalancesData from 'components/perps/BalancesTable/usePerpsBalancesData' -import Table from 'components/common/Table' +import { SearchParams } from 'types/enums/searchParams' +import { getSearchParamsObject } from 'utils/route' export default function PerpsBalancesTable() { const data = usePerpsBalancesData() const columns = usePerpsBalancesColumns() + const [searchParams, setSearchParams] = useSearchParams() - return
+ const onClickRow = useCallback((denom: string) => { + const params = getSearchParamsObject(searchParams) + setSearchParams({ + ...params, + [SearchParams.PERPS_MARKET]: denom, + }) + }, []) + + return ( +
+ ) } diff --git a/src/components/portfolio/Account/BreadCrumbs.tsx b/src/components/portfolio/Account/BreadCrumbs.tsx index 536d648e..b2d3f83f 100644 --- a/src/components/portfolio/Account/BreadCrumbs.tsx +++ b/src/components/portfolio/Account/BreadCrumbs.tsx @@ -19,7 +19,9 @@ export default function PortfolioAccountPageHeader(props: Props) { Portfolio - +
+ +
Credit Account {props.accountId} ) diff --git a/src/components/portfolio/Card/Skeleton.tsx b/src/components/portfolio/Card/Skeleton.tsx index 3fb0e2e6..838cda79 100644 --- a/src/components/portfolio/Card/Skeleton.tsx +++ b/src/components/portfolio/Card/Skeleton.tsx @@ -2,9 +2,9 @@ import React from 'react' import HealthBar from 'components/account/Health/HealthBar' import Card from 'components/common/Card' -import HLSTag from 'components/hls/HLSTag' import Text from 'components/common/Text' import TitleAndSubCell from 'components/common/TitleAndSubCell' +import HLSTag from 'components/hls/HLSTag' interface Props { stats: { title: React.ReactNode; sub: string }[] @@ -33,7 +33,7 @@ export default function Skeleton(props: Props) { ))} -
+
diff --git a/src/components/portfolio/SummarySkeleton.tsx b/src/components/portfolio/SummarySkeleton.tsx index a8aa1adc..0c665e9d 100644 --- a/src/components/portfolio/SummarySkeleton.tsx +++ b/src/components/portfolio/SummarySkeleton.tsx @@ -3,10 +3,10 @@ import React from 'react' import HealthBar from 'components/account/Health/HealthBar' import HealthIcon from 'components/account/Health/HealthIcon' import Card from 'components/common/Card' -import HLSTag from 'components/hls/HLSTag' import Loading from 'components/common/Loading' import Text from 'components/common/Text' import TitleAndSubCell from 'components/common/TitleAndSubCell' +import HLSTag from 'components/hls/HLSTag' import useAccount from 'hooks/accounts/useAccount' import { DEFAULT_PORTFOLIO_STATS } from 'utils/constants' @@ -31,9 +31,11 @@ export default function SummarySkeleton(props: Props) { {account?.kind === 'high_levered_strategy' && }
{health !== undefined && healthFactor !== undefined && ( -
- - +
+ +
+ +
)}
diff --git a/src/types/interfaces/components/DropDownMenu.d.ts b/src/types/interfaces/components/DropDownMenu.d.ts index 58bcd761..193a9387 100644 --- a/src/types/interfaces/components/DropDownMenu.d.ts +++ b/src/types/interfaces/components/DropDownMenu.d.ts @@ -2,4 +2,6 @@ interface DropDownItem { icon: import('react').ReactNode onClick: () => void text: string + disabled?: boolean + disabledTooltip?: string } diff --git a/src/utils/url.ts b/src/utils/url.ts index 807c2ed0..a3a331c9 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -1,4 +1,8 @@ export const getUrl = (baseUrl: string, path: string): string => { + const isPlaceholder = baseUrl.split('APP_').length > 1 + + if (isPlaceholder) return baseUrl + '/' + path + const url = new URL(baseUrl) if (process.env.NEXT_PUBLIC_API_KEY)