diff --git a/packages/ui/app/_components/dialogs/manage/DialogWrapper.tsx b/packages/ui/app/_components/dialogs/manage/DialogWrapper.tsx new file mode 100644 index 000000000..26b8a6e2c --- /dev/null +++ b/packages/ui/app/_components/dialogs/manage/DialogWrapper.tsx @@ -0,0 +1,37 @@ +'use client'; + +import { Dialog } from '@ui/components/ui/dialog'; +import { useManageDialogContext } from '@ui/context/ManageDialogContext'; + +import type { ActiveTab } from '.'; + +const DialogWrapper = ({ + isOpen, + setIsOpen, + children, + setCurrentActiveTab +}: { + isOpen: boolean; + setIsOpen: (open: boolean) => void; + children: React.ReactNode; + setCurrentActiveTab: (tab: ActiveTab) => void; +}) => { + const { resetTransactionSteps } = useManageDialogContext(); + + return ( + { + setIsOpen(open); + if (!open) { + resetTransactionSteps(); + setCurrentActiveTab('supply'); + } + }} + > + {children} + + ); +}; + +export default DialogWrapper; diff --git a/packages/ui/app/_components/dialogs/manage/ManageDialogTabs.tsx b/packages/ui/app/_components/dialogs/manage/ManageDialogTabs.tsx new file mode 100644 index 000000000..4d64cff8e --- /dev/null +++ b/packages/ui/app/_components/dialogs/manage/ManageDialogTabs.tsx @@ -0,0 +1,248 @@ +'use client'; +import { useMemo } from 'react'; + +import Image from 'next/image'; + +import { type Address, formatEther, formatUnits } from 'viem'; + +import { DialogContent } from '@ui/components/ui/dialog'; +import { + Tabs, + TabsList, + TabsTrigger, + TabsContent +} from '@ui/components/ui/tabs'; +import { useManageDialogContext } from '@ui/context/ManageDialogContext'; +import { useBorrowCapsDataForAsset } from '@ui/hooks/ionic/useBorrowCapsDataForAsset'; +import { useSupplyCapsDataForAsset } from '@ui/hooks/ionic/useSupplyCapsDataForPool'; +import { useUsdPrice } from '@ui/hooks/useAllUsdPrices'; +import { useMaxBorrowAmount } from '@ui/hooks/useMaxBorrowAmount'; +import { useMaxRepayAmount } from '@ui/hooks/useMaxRepayAmount'; +import { useMaxSupplyAmount } from '@ui/hooks/useMaxSupplyAmount'; +import { useMaxWithdrawAmount } from '@ui/hooks/useMaxWithdrawAmount'; +import type { MarketData } from '@ui/types/TokensDataMap'; + +import BorrowTab from './BorrowTab'; +import RepayTab from './RepayTab'; +import SupplyTab from './SupplyTab'; +import WithdrawTab from './WithdrawTab'; +import AnimateHeight from '../../AnimateHeight'; + +import type { ActiveTab } from '.'; + +const ManageDialogTabs = ({ + selectedMarketData, + comptrollerAddress, + isBorrowDisabled, + currentActiveTab, + setCurrentActiveTab, + setSwapWidgetOpen, + chainId +}: { + selectedMarketData: MarketData; + comptrollerAddress: Address; + isBorrowDisabled: boolean; + currentActiveTab: ActiveTab; + setCurrentActiveTab: (tab: ActiveTab) => void; + setSwapWidgetOpen: (open: boolean) => void; + chainId: number; +}) => { + const { data: usdPrice } = useUsdPrice(chainId.toString()); + const { data: maxSupplyAmount, isLoading: isLoadingMaxSupply } = + useMaxSupplyAmount(selectedMarketData, comptrollerAddress, chainId); + + const { data: maxRepayAmount, isLoading: isLoadingMaxRepayAmount } = + useMaxRepayAmount(selectedMarketData, chainId); + + const { data: maxBorrowAmount, isLoading: isLoadingMaxBorrowAmount } = + useMaxBorrowAmount(selectedMarketData, comptrollerAddress, chainId); + + const { data: maxWithdrawAmount, isLoading: isLoadingMaxWithdrawAmount } = + useMaxWithdrawAmount(selectedMarketData, chainId); + + // Memoize calculations + const pricePerSingleAsset = useMemo( + () => + parseFloat(formatEther(selectedMarketData.underlyingPrice)) * + (usdPrice ?? 0), + [selectedMarketData.underlyingPrice, usdPrice] + ); + + const { data: supplyCap } = useSupplyCapsDataForAsset( + comptrollerAddress, + selectedMarketData.cToken, + chainId + ); + + const supplyCapAsNumber = useMemo( + () => + parseFloat( + formatUnits( + supplyCap?.supplyCaps ?? 0n, + selectedMarketData.underlyingDecimals + ) + ), + [supplyCap?.supplyCaps, selectedMarketData.underlyingDecimals] + ); + + const supplyCapAsFiat = useMemo( + () => pricePerSingleAsset * supplyCapAsNumber, + [pricePerSingleAsset, supplyCapAsNumber] + ); + + const totalSupplyAsNumber = useMemo( + () => + parseFloat( + formatUnits( + selectedMarketData.totalSupply, + selectedMarketData.underlyingDecimals + ) + ), + [selectedMarketData.totalSupply, selectedMarketData.underlyingDecimals] + ); + + const { data: borrowCap } = useBorrowCapsDataForAsset( + selectedMarketData.cToken, + chainId + ); + + const borrowCapAsNumber = useMemo( + () => + parseFloat( + formatUnits( + borrowCap?.totalBorrowCap ?? 0n, + selectedMarketData.underlyingDecimals + ) + ), + [borrowCap?.totalBorrowCap, selectedMarketData.underlyingDecimals] + ); + + const borrowCapAsFiat = useMemo( + () => pricePerSingleAsset * borrowCapAsNumber, + [pricePerSingleAsset, borrowCapAsNumber] + ); + + const totalBorrowAsNumber = useMemo( + () => + parseFloat( + formatUnits( + selectedMarketData.totalBorrow, + selectedMarketData.underlyingDecimals + ) + ), + [selectedMarketData.totalBorrow, selectedMarketData.underlyingDecimals] + ); + + const TabsComponent = () => { + const { setActive } = useManageDialogContext(); + + const handleTabChange = (value: string) => { + const newTab = value as ActiveTab; + setCurrentActiveTab(newTab); + setActive(newTab); + }; + + return ( +
+ + + Supply + + Borrow + + + Repay + + Withdraw + + + + + + + + + + + + + + + +
+ ); + }; + + return ( + +
+ modlogo +
+ + + +
+ ); +}; + +export default ManageDialogTabs; diff --git a/packages/ui/app/_components/dialogs/manage/SupplyTab.tsx b/packages/ui/app/_components/dialogs/manage/SupplyTab.tsx index 0aa3bb293..77be2ef14 100644 --- a/packages/ui/app/_components/dialogs/manage/SupplyTab.tsx +++ b/packages/ui/app/_components/dialogs/manage/SupplyTab.tsx @@ -42,7 +42,6 @@ const SupplyTab = ({ const { selectedMarketData, resetTransactionSteps, - transactionSteps: supplyTxSteps, chainId, comptrollerAddress, updatedValues, @@ -52,11 +51,7 @@ const SupplyTab = ({ getStepsForTypes } = useManageDialogContext(); - const { - enableCollateral, - handleCollateralToggle, - transactionSteps: collateralTxSteps - } = useCollateralToggle({ + const { enableCollateral, handleCollateralToggle } = useCollateralToggle({ selectedMarketData, comptrollerAddress, onSuccess: refetchUsedQueries diff --git a/packages/ui/app/_components/dialogs/manage/index.tsx b/packages/ui/app/_components/dialogs/manage/index.tsx index ab9d5be45..921595429 100644 --- a/packages/ui/app/_components/dialogs/manage/index.tsx +++ b/packages/ui/app/_components/dialogs/manage/index.tsx @@ -1,37 +1,17 @@ 'use client'; -import { useEffect, useMemo, useState } from 'react'; +import { useState } from 'react'; import dynamic from 'next/dynamic'; -import Image from 'next/image'; -import { type Address, formatEther, formatUnits } from 'viem'; +import { type Address } from 'viem'; import { useChainId } from 'wagmi'; -import { Dialog, DialogContent } from '@ui/components/ui/dialog'; -import { - Tabs, - TabsList, - TabsTrigger, - TabsContent -} from '@ui/components/ui/tabs'; -import { - ManageDialogProvider, - useManageDialogContext -} from '@ui/context/ManageDialogContext'; -import { useBorrowCapsDataForAsset } from '@ui/hooks/ionic/useBorrowCapsDataForAsset'; -import { useSupplyCapsDataForAsset } from '@ui/hooks/ionic/useSupplyCapsDataForPool'; -import { useUsdPrice } from '@ui/hooks/useAllUsdPrices'; -import { useMaxBorrowAmount } from '@ui/hooks/useMaxBorrowAmount'; -import { useMaxRepayAmount } from '@ui/hooks/useMaxRepayAmount'; +import { ManageDialogProvider } from '@ui/context/ManageDialogContext'; import { useMaxSupplyAmount } from '@ui/hooks/useMaxSupplyAmount'; -import { useMaxWithdrawAmount } from '@ui/hooks/useMaxWithdrawAmount'; import type { MarketData } from '@ui/types/TokensDataMap'; -import BorrowTab from './BorrowTab'; -import RepayTab from './RepayTab'; -import SupplyTab from './SupplyTab'; -import WithdrawTab from './WithdrawTab'; -import AnimateHeight from '../../AnimateHeight'; +import DialogWrapper from './DialogWrapper'; +import ManageDialogTabs from './ManageDialogTabs'; const SwapWidget = dynamic(() => import('../../markets/SwapWidget'), { ssr: false @@ -46,7 +26,7 @@ export enum HFPStatus { WARNING = 'WARNING' } -interface IPopup { +interface ManageDialogProps { isOpen: boolean; setIsOpen: (open: boolean) => void; comptrollerAddress: Address; @@ -62,214 +42,37 @@ const ManageDialog = ({ comptrollerAddress, isBorrowDisabled = false, activeTab = 'supply' -}: IPopup) => { +}: ManageDialogProps) => { const [swapWidgetOpen, setSwapWidgetOpen] = useState(false); const chainId = useChainId(); - const { data: usdPrice } = useUsdPrice(chainId.toString()); const [currentActiveTab, setCurrentActiveTab] = useState(activeTab); - - const pricePerSingleAsset = useMemo( - () => - parseFloat(formatEther(selectedMarketData.underlyingPrice)) * - (usdPrice ?? 0), - [selectedMarketData, usdPrice] - ); - const { data: supplyCap } = useSupplyCapsDataForAsset( + const { refetch: refetchMaxSupplyAmount } = useMaxSupplyAmount( + selectedMarketData, comptrollerAddress, - selectedMarketData.cToken, - chainId - ); - const supplyCapAsNumber = useMemo( - () => - parseFloat( - formatUnits( - supplyCap?.supplyCaps ?? 0n, - selectedMarketData.underlyingDecimals - ) - ), - [supplyCap, selectedMarketData.underlyingDecimals] - ); - const supplyCapAsFiat = useMemo( - () => pricePerSingleAsset * supplyCapAsNumber, - [pricePerSingleAsset, supplyCapAsNumber] - ); - const totalSupplyAsNumber = useMemo( - () => - parseFloat( - formatUnits( - selectedMarketData.totalSupply, - selectedMarketData.underlyingDecimals - ) - ), - [selectedMarketData.totalSupply, selectedMarketData.underlyingDecimals] - ); - const { data: borrowCap } = useBorrowCapsDataForAsset( - selectedMarketData.cToken, chainId ); - const borrowCapAsNumber = useMemo( - () => - parseFloat( - formatUnits( - borrowCap?.totalBorrowCap ?? 0n, - selectedMarketData.underlyingDecimals - ) - ), - [borrowCap, selectedMarketData.underlyingDecimals] - ); - const borrowCapAsFiat = useMemo( - () => pricePerSingleAsset * borrowCapAsNumber, - [pricePerSingleAsset, borrowCapAsNumber] - ); - const totalBorrowAsNumber = useMemo( - () => - parseFloat( - formatUnits( - selectedMarketData.totalBorrow, - selectedMarketData.underlyingDecimals - ) - ), - [selectedMarketData.totalBorrow, selectedMarketData.underlyingDecimals] - ); - - const { - data: maxSupplyAmount, - isLoading: isLoadingMaxSupply, - refetch: refetchMaxSupplyAmount - } = useMaxSupplyAmount(selectedMarketData, comptrollerAddress, chainId); - const { data: maxRepayAmount, isLoading: isLoadingMaxRepayAmount } = - useMaxRepayAmount(selectedMarketData, chainId); - const { data: maxBorrowAmount, isLoading: isLoadingMaxBorrowAmount } = - useMaxBorrowAmount(selectedMarketData, comptrollerAddress, chainId); - const { data: maxWithdrawAmount, isLoading: isLoadingMaxWithdrawAmount } = - useMaxWithdrawAmount(selectedMarketData, chainId); - - const TabsWithContext = ({ - isBorrowDisabled - }: { - isBorrowDisabled: boolean; - }) => { - const { setActive } = useManageDialogContext(); - - // Handle tab change with persistence - const handleTabChange = (value: string) => { - const newTab = value as ActiveTab; - setCurrentActiveTab(newTab); - setActive(newTab); - }; - - return ( -
- - - Supply - - Borrow - - - Repay - - Withdraw - - - - - - - - - - - - - - - -
- ); - }; return ( setIsOpen(false)} selectedMarketData={selectedMarketData} > - - -
- modlogo -
- - - - -
-
+ + setSwapWidgetOpen(false)} diff --git a/packages/ui/context/ManageDialogContext.tsx b/packages/ui/context/ManageDialogContext.tsx index ef10a2c22..2ae312213 100644 --- a/packages/ui/context/ManageDialogContext.tsx +++ b/packages/ui/context/ManageDialogContext.tsx @@ -12,10 +12,7 @@ import { useQueryClient } from '@tanstack/react-query'; import { type Address, formatUnits } from 'viem'; import { useChainId } from 'wagmi'; -import { - TransactionStep, - useTransactionSteps -} from '@ui/app/_components/dialogs/manage/TransactionStepsHandler'; +import type { TransactionStep } from '@ui/app/_components/dialogs/manage/TransactionStepsHandler'; import { useMultiIonic } from '@ui/context/MultiIonicContext'; import useUpdatedUserAssets from '@ui/hooks/ionic/useUpdatedUserAssets'; import type { MarketData } from '@ui/types/TokensDataMap'; @@ -101,9 +98,8 @@ const ManageDialogContext = createContext( export const ManageDialogProvider: React.FC<{ selectedMarketData: MarketData; comptrollerAddress: Address; - closePopup: () => void; children: React.ReactNode; -}> = ({ selectedMarketData, comptrollerAddress, closePopup, children }) => { +}> = ({ selectedMarketData, comptrollerAddress, children }) => { const { currentSdk } = useMultiIonic(); const chainId = useChainId(); const [active, setActive] = useState('supply'); @@ -146,24 +142,26 @@ export const ManageDialogProvider: React.FC<{ const queryClient = useQueryClient(); - const refetchUsedQueries = async () => { - queryClient.invalidateQueries({ queryKey: ['useFusePoolData'] }); - queryClient.invalidateQueries({ queryKey: ['useBorrowMinimum'] }); - queryClient.invalidateQueries({ queryKey: ['useUsdPrice'] }); - queryClient.invalidateQueries({ queryKey: ['useAllUsdPrices'] }); - queryClient.invalidateQueries({ queryKey: ['useTotalSupplyAPYs'] }); - queryClient.invalidateQueries({ queryKey: ['useUpdatedUserAssets'] }); - queryClient.invalidateQueries({ queryKey: ['useMaxSupplyAmount'] }); - queryClient.invalidateQueries({ queryKey: ['useMaxWithdrawAmount'] }); - queryClient.invalidateQueries({ queryKey: ['useMaxBorrowAmount'] }); - queryClient.invalidateQueries({ queryKey: ['useMaxRepayAmount'] }); - queryClient.invalidateQueries({ - queryKey: ['useSupplyCapsDataForPool'] - }); - queryClient.invalidateQueries({ - queryKey: ['useBorrowCapsDataForAsset'] + const refetchUsedQueries = useCallback(async () => { + const queryKeys = [ + 'useFusePoolData', + 'useBorrowMinimum', + 'useUsdPrice', + 'useAllUsdPrices', + 'useTotalSupplyAPYs', + 'useUpdatedUserAssets', + 'useMaxSupplyAmount', + 'useMaxWithdrawAmount', + 'useMaxBorrowAmount', + 'useMaxRepayAmount', + 'useSupplyCapsDataForPool', + 'useBorrowCapsDataForAsset' + ]; + + queryKeys.forEach((key) => { + queryClient.invalidateQueries({ queryKey: [key] }); }); - }; + }, [queryClient]); const updatedValues = useMemo(() => { const blocksPerMinute = getBlockTimePerMinuteByChainId(chainId);