From 2a21c467374f0acf56450837764ec374ab2fb395 Mon Sep 17 00:00:00 2001 From: vidvidvid <weetopol@gmail.com> Date: Wed, 4 Dec 2024 21:44:52 +0100 Subject: [PATCH] fix resetting values on close --- .../dialogs/manage/DialogWrapper.tsx | 37 +++ .../dialogs/manage/ManageDialogTabs.tsx | 248 ++++++++++++++++++ .../_components/dialogs/manage/SupplyTab.tsx | 7 +- .../app/_components/dialogs/manage/index.tsx | 243 ++--------------- packages/ui/context/ManageDialogContext.tsx | 44 ++-- 5 files changed, 330 insertions(+), 249 deletions(-) create mode 100644 packages/ui/app/_components/dialogs/manage/DialogWrapper.tsx create mode 100644 packages/ui/app/_components/dialogs/manage/ManageDialogTabs.tsx 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 ( + <Dialog + open={isOpen} + onOpenChange={(open) => { + setIsOpen(open); + if (!open) { + resetTransactionSteps(); + setCurrentActiveTab('supply'); + } + }} + > + {children} + </Dialog> + ); +}; + +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 ( + <div className="tabs-container"> + <Tabs + defaultValue={currentActiveTab} + onValueChange={handleTabChange} + value={currentActiveTab} + > + <TabsList className="grid w-full grid-cols-4"> + <TabsTrigger value="supply">Supply</TabsTrigger> + <TabsTrigger + value="borrow" + disabled={isBorrowDisabled} + > + Borrow + </TabsTrigger> + <TabsTrigger + value="repay" + disabled={isBorrowDisabled} + > + Repay + </TabsTrigger> + <TabsTrigger value="withdraw">Withdraw</TabsTrigger> + </TabsList> + + <TabsContent + value="supply" + className="mt-2" + > + <SupplyTab + maxAmount={maxSupplyAmount?.bigNumber ?? 0n} + isLoadingMax={isLoadingMaxSupply} + totalStats={{ + capAmount: supplyCapAsNumber, + totalAmount: totalSupplyAsNumber, + capFiat: supplyCapAsFiat, + totalFiat: selectedMarketData.totalSupplyFiat + }} + setSwapWidgetOpen={setSwapWidgetOpen} + /> + </TabsContent> + <TabsContent value="borrow"> + <BorrowTab + maxAmount={maxBorrowAmount?.bigNumber ?? 0n} + isLoadingMax={isLoadingMaxBorrowAmount} + totalStats={{ + capAmount: borrowCapAsNumber, + totalAmount: totalBorrowAsNumber, + capFiat: borrowCapAsFiat, + totalFiat: selectedMarketData.totalBorrowFiat + }} + /> + </TabsContent> + <TabsContent value="repay"> + <RepayTab + maxAmount={maxRepayAmount ?? 0n} + isLoadingMax={isLoadingMaxRepayAmount} + totalStats={{ + capAmount: borrowCapAsNumber, + totalAmount: totalBorrowAsNumber, + capFiat: borrowCapAsFiat, + totalFiat: selectedMarketData.totalBorrowFiat + }} + /> + </TabsContent> + <TabsContent value="withdraw"> + <WithdrawTab + maxAmount={maxWithdrawAmount ?? 0n} + isLoadingMax={isLoadingMaxWithdrawAmount} + totalStats={{ + capAmount: supplyCapAsNumber, + totalAmount: totalSupplyAsNumber, + capFiat: supplyCapAsFiat, + totalFiat: selectedMarketData.totalSupplyFiat + }} + /> + </TabsContent> + </Tabs> + </div> + ); + }; + + return ( + <DialogContent + maxWidth="800px" + className="bg-grayUnselect" + fullWidth + > + <div className="flex w-20 mx-auto relative text-center"> + <Image + alt="modlogo" + className="mx-auto" + height={32} + src={`/img/symbols/32/color/${selectedMarketData?.underlyingSymbol.toLowerCase()}.png`} + width={32} + /> + </div> + <AnimateHeight> + <TabsComponent /> + </AnimateHeight> + </DialogContent> + ); +}; + +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>(activeTab); - - const pricePerSingleAsset = useMemo<number>( - () => - parseFloat(formatEther(selectedMarketData.underlyingPrice)) * - (usdPrice ?? 0), - [selectedMarketData, usdPrice] - ); - const { data: supplyCap } = useSupplyCapsDataForAsset( + const { refetch: refetchMaxSupplyAmount } = useMaxSupplyAmount( + selectedMarketData, comptrollerAddress, - selectedMarketData.cToken, - chainId - ); - const supplyCapAsNumber = useMemo<number>( - () => - parseFloat( - formatUnits( - supplyCap?.supplyCaps ?? 0n, - selectedMarketData.underlyingDecimals - ) - ), - [supplyCap, selectedMarketData.underlyingDecimals] - ); - const supplyCapAsFiat = useMemo<number>( - () => pricePerSingleAsset * supplyCapAsNumber, - [pricePerSingleAsset, supplyCapAsNumber] - ); - const totalSupplyAsNumber = useMemo<number>( - () => - parseFloat( - formatUnits( - selectedMarketData.totalSupply, - selectedMarketData.underlyingDecimals - ) - ), - [selectedMarketData.totalSupply, selectedMarketData.underlyingDecimals] - ); - const { data: borrowCap } = useBorrowCapsDataForAsset( - selectedMarketData.cToken, chainId ); - const borrowCapAsNumber = useMemo<number>( - () => - parseFloat( - formatUnits( - borrowCap?.totalBorrowCap ?? 0n, - selectedMarketData.underlyingDecimals - ) - ), - [borrowCap, selectedMarketData.underlyingDecimals] - ); - const borrowCapAsFiat = useMemo<number>( - () => pricePerSingleAsset * borrowCapAsNumber, - [pricePerSingleAsset, borrowCapAsNumber] - ); - const totalBorrowAsNumber = useMemo<number>( - () => - 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 ( - <div className="tabs-container"> - <Tabs - defaultValue={currentActiveTab} - onValueChange={handleTabChange} - value={currentActiveTab} - > - <TabsList className="grid w-full grid-cols-4"> - <TabsTrigger value="supply">Supply</TabsTrigger> - <TabsTrigger - value="borrow" - disabled={isBorrowDisabled} - > - Borrow - </TabsTrigger> - <TabsTrigger - value="repay" - disabled={isBorrowDisabled} - > - Repay - </TabsTrigger> - <TabsTrigger value="withdraw">Withdraw</TabsTrigger> - </TabsList> - - <TabsContent - value="supply" - className="mt-2" - > - <SupplyTab - maxAmount={maxSupplyAmount?.bigNumber ?? 0n} - isLoadingMax={isLoadingMaxSupply} - totalStats={{ - capAmount: supplyCapAsNumber, - totalAmount: totalSupplyAsNumber, - capFiat: supplyCapAsFiat, - totalFiat: selectedMarketData.totalSupplyFiat - }} - setSwapWidgetOpen={setSwapWidgetOpen} - /> - </TabsContent> - <TabsContent value="borrow"> - <BorrowTab - maxAmount={maxBorrowAmount?.bigNumber ?? 0n} - isLoadingMax={isLoadingMaxBorrowAmount} - totalStats={{ - capAmount: borrowCapAsNumber, - totalAmount: totalBorrowAsNumber, - capFiat: borrowCapAsFiat, - totalFiat: selectedMarketData.totalBorrowFiat - }} - /> - </TabsContent> - <TabsContent value="repay"> - <RepayTab - maxAmount={maxRepayAmount ?? 0n} - isLoadingMax={isLoadingMaxRepayAmount} - totalStats={{ - capAmount: borrowCapAsNumber, - totalAmount: totalBorrowAsNumber, - capFiat: borrowCapAsFiat, - totalFiat: selectedMarketData.totalBorrowFiat - }} - /> - </TabsContent> - <TabsContent value="withdraw"> - <WithdrawTab - maxAmount={maxWithdrawAmount ?? 0n} - isLoadingMax={isLoadingMaxWithdrawAmount} - totalStats={{ - capAmount: supplyCapAsNumber, - totalAmount: totalSupplyAsNumber, - capFiat: supplyCapAsFiat, - totalFiat: selectedMarketData.totalSupplyFiat - }} - /> - </TabsContent> - </Tabs> - </div> - ); - }; return ( <ManageDialogProvider comptrollerAddress={comptrollerAddress} - closePopup={() => setIsOpen(false)} selectedMarketData={selectedMarketData} > - <Dialog - open={isOpen} - onOpenChange={setIsOpen} + <DialogWrapper + isOpen={isOpen} + setIsOpen={setIsOpen} + setCurrentActiveTab={setCurrentActiveTab} > - <DialogContent - maxWidth="800px" - className="bg-grayUnselect" - fullWidth - > - <div className="flex w-20 mx-auto relative text-center"> - <Image - alt="modlogo" - className="mx-auto" - height={32} - src={`/img/symbols/32/color/${selectedMarketData?.underlyingSymbol.toLowerCase()}.png`} - width={32} - /> - </div> - - <AnimateHeight> - <TabsWithContext isBorrowDisabled={isBorrowDisabled} /> - </AnimateHeight> - </DialogContent> - </Dialog> + <ManageDialogTabs + selectedMarketData={selectedMarketData} + comptrollerAddress={comptrollerAddress} + isBorrowDisabled={isBorrowDisabled} + currentActiveTab={currentActiveTab} + setCurrentActiveTab={setCurrentActiveTab} + setSwapWidgetOpen={setSwapWidgetOpen} + chainId={chainId} + /> + </DialogWrapper> <SwapWidget close={() => 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<ManageDialogContextType | undefined>( 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<ActiveTab>('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);