From a15f5cbc7cfed047cbbb7734ff8f00bd84b479a0 Mon Sep 17 00:00:00 2001 From: Daniel Schiavini Date: Tue, 2 Dec 2025 17:33:36 +0100 Subject: [PATCH 01/15] refactor: manage loan tabs --- .../PageLoanManage/LoanBorrowMore/index.tsx | 24 +-- .../LoanCollateralAdd/index.tsx | 5 + .../LoanCollateralRemove/index.tsx | 5 + .../PageLoanManage/LoanRepay/index.tsx | 9 + .../LoanSelfLiquidation/index.tsx | 2 +- .../PageLoanManage/ManageLoanTabs.tsx | 86 ++++++++++ .../lend/components/PageLoanManage/Page.tsx | 4 +- .../lend/components/PageLoanManage/index.tsx | 157 ------------------ apps/main/src/lend/types/lend.types.ts | 4 +- .../components/AddCollateralForm.tsx | 2 +- .../components/RemoveCollateralForm.tsx | 2 +- .../manage-loan/components/RepayForm.tsx | 68 ++++---- .../manage-loan/hooks/useAddCollateralForm.ts | 2 +- .../hooks/useRemoveCollateralForm.ts | 2 +- .../manage-loan/hooks/useRepayForm.ts | 2 +- .../src/llamalend/mutations/repay.mutation.ts | 2 +- .../llamalend/mutations/useLlammaMutation.ts | 4 +- .../loan/components/PageLoanCreate/index.tsx | 2 +- .../src/shared/ui/FormTabs/FormTabs.tsx | 76 +++++++++ 19 files changed, 249 insertions(+), 209 deletions(-) create mode 100644 apps/main/src/lend/components/PageLoanManage/ManageLoanTabs.tsx delete mode 100644 apps/main/src/lend/components/PageLoanManage/index.tsx create mode 100644 packages/curve-ui-kit/src/shared/ui/FormTabs/FormTabs.tsx diff --git a/apps/main/src/lend/components/PageLoanManage/LoanBorrowMore/index.tsx b/apps/main/src/lend/components/PageLoanManage/LoanBorrowMore/index.tsx index 91ea35d726..a0b2b5e301 100644 --- a/apps/main/src/lend/components/PageLoanManage/LoanBorrowMore/index.tsx +++ b/apps/main/src/lend/components/PageLoanManage/LoanBorrowMore/index.tsx @@ -26,6 +26,7 @@ import { useLoanExists } from '@/llamalend/queries/loan-exists' import Stack from '@mui/material/Stack' import Typography from '@mui/material/Typography' import AlertBox from '@ui/AlertBox' +import { AppFormContentWrapper } from '@ui/AppForm' import { getActiveStep } from '@ui/Stepper/helpers' import Stepper from '@ui/Stepper/Stepper' import type { Step } from '@ui/Stepper/types' @@ -40,17 +41,9 @@ import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' const { Spacing } = SizesAndSpaces -const LoanBorrowMore = ({ - rChainId, - rOwmId, - isLeverage = false, - isLoaded, - api, - market, - userActiveKey, -}: PageContentProps & { isLeverage?: boolean }) => { +const LoanBorrowMore = ({ rChainId, rOwmId, isLoaded, api, market, userActiveKey }: PageContentProps) => { const isSubscribed = useRef(false) - + const isLeverage = market?.leverage?.hasLeverage() ?? false const activeKey = useStore((state) => state.loanBorrowMore.activeKey) const activeKeyMax = useStore((state) => state.loanBorrowMore.activeKeyMax) const detailInfoLeverage = useStore((state) => state.loanBorrowMore.detailInfoLeverage[activeKey]) @@ -436,3 +429,14 @@ const LoanBorrowMore = ({ } export default LoanBorrowMore + +/** + * The new implementation of LoanBorrowMore with mui isn't ready yet. For now, we wrap the old one for styling. + */ +export const LoanBorrowMoreWrapped = (props: PageContentProps) => ( + t.design.Layer[1].Fill }}> + + + + +) diff --git a/apps/main/src/lend/components/PageLoanManage/LoanCollateralAdd/index.tsx b/apps/main/src/lend/components/PageLoanManage/LoanCollateralAdd/index.tsx index 7fb4485c0b..eea70678a7 100644 --- a/apps/main/src/lend/components/PageLoanManage/LoanCollateralAdd/index.tsx +++ b/apps/main/src/lend/components/PageLoanManage/LoanCollateralAdd/index.tsx @@ -19,6 +19,7 @@ import useStore from '@/lend/store/useStore' import { Api, OneWayMarketTemplate, PageContentProps } from '@/lend/types/lend.types' import { _showNoLoanFound } from '@/lend/utils/helpers' import { DEFAULT_HEALTH_MODE } from '@/llamalend/constants' +import { AddCollateralForm } from '@/llamalend/features/manage-loan/components/AddCollateralForm' import { useLoanExists } from '@/llamalend/queries/loan-exists' import AlertBox from '@ui/AlertBox' import { getActiveStep } from '@ui/Stepper/helpers' @@ -258,3 +259,7 @@ const LoanCollateralAdd = ({ rChainId, rOwmId, api, isLoaded, market, userActive } export default LoanCollateralAdd + +export const LoanAddCollateralTab = ({ rChainId, market, isLoaded }: PageContentProps) => ( + +) diff --git a/apps/main/src/lend/components/PageLoanManage/LoanCollateralRemove/index.tsx b/apps/main/src/lend/components/PageLoanManage/LoanCollateralRemove/index.tsx index aa959653e8..0a2e54f410 100644 --- a/apps/main/src/lend/components/PageLoanManage/LoanCollateralRemove/index.tsx +++ b/apps/main/src/lend/components/PageLoanManage/LoanCollateralRemove/index.tsx @@ -21,6 +21,7 @@ import useStore from '@/lend/store/useStore' import { Api, OneWayMarketTemplate, PageContentProps } from '@/lend/types/lend.types' import { _showNoLoanFound } from '@/lend/utils/helpers' import { DEFAULT_HEALTH_MODE } from '@/llamalend/constants' +import { RemoveCollateralForm } from '@/llamalend/features/manage-loan/components/RemoveCollateralForm' import type { HealthMode } from '@/llamalend/llamalend.types' import { useLoanExists } from '@/llamalend/queries/loan-exists' import AlertBox from '@ui/AlertBox' @@ -296,3 +297,7 @@ const LoanCollateralRemove = ({ rChainId, rOwmId, isLoaded, api, market, userAct } export default LoanCollateralRemove + +export const LoanRemoveCollateralTab = ({ rChainId, market, isLoaded }: PageContentProps) => ( + +) diff --git a/apps/main/src/lend/components/PageLoanManage/LoanRepay/index.tsx b/apps/main/src/lend/components/PageLoanManage/LoanRepay/index.tsx index aa58edd63f..8c4c51015e 100644 --- a/apps/main/src/lend/components/PageLoanManage/LoanRepay/index.tsx +++ b/apps/main/src/lend/components/PageLoanManage/LoanRepay/index.tsx @@ -20,6 +20,7 @@ import { Api, FormError, type MarketUrlParams, OneWayMarketTemplate, PageContent import { _showNoLoanFound } from '@/lend/utils/helpers' import { getCollateralListPathname } from '@/lend/utils/utilsRouter' import { DEFAULT_HEALTH_MODE } from '@/llamalend/constants' +import { RepayForm } from '@/llamalend/features/manage-loan/components/RepayForm' import type { HealthMode } from '@/llamalend/llamalend.types' import { useLoanExists } from '@/llamalend/queries/loan-exists' import Stack from '@mui/material/Stack' @@ -537,3 +538,11 @@ const LoanRepay = ({ } export default LoanRepay + +export const LoanRepayFromWalletTab = ({ rChainId, market, isLoaded }: PageContentProps) => ( + +) + +export const LoanRepayFromCollateralTab = ({ rChainId, market, isLoaded }: PageContentProps) => ( + +) diff --git a/apps/main/src/lend/components/PageLoanManage/LoanSelfLiquidation/index.tsx b/apps/main/src/lend/components/PageLoanManage/LoanSelfLiquidation/index.tsx index b1647b2693..15efbecd39 100644 --- a/apps/main/src/lend/components/PageLoanManage/LoanSelfLiquidation/index.tsx +++ b/apps/main/src/lend/components/PageLoanManage/LoanSelfLiquidation/index.tsx @@ -45,7 +45,7 @@ const LoanSelfLiquidation = ({ market, userActiveKey, params, -}: PageContentProps & { params: MarketUrlParams }) => { +}: PageContentProps) => { const isSubscribed = useRef(false) const formEstGas = useStore((state) => state.loanSelfLiquidation.formEstGas) const formStatus = useStore((state) => state.loanSelfLiquidation.formStatus) diff --git a/apps/main/src/lend/components/PageLoanManage/ManageLoanTabs.tsx b/apps/main/src/lend/components/PageLoanManage/ManageLoanTabs.tsx new file mode 100644 index 0000000000..88d81c7440 --- /dev/null +++ b/apps/main/src/lend/components/PageLoanManage/ManageLoanTabs.tsx @@ -0,0 +1,86 @@ +import LoanBorrowMore, { LoanBorrowMoreWrapped } from '@/lend/components/PageLoanManage/LoanBorrowMore' +import LoanCollateralAdd, { LoanAddCollateralTab } from '@/lend/components/PageLoanManage/LoanCollateralAdd' +import LoanCollateralRemove, { LoanRemoveCollateralTab } from '@/lend/components/PageLoanManage/LoanCollateralRemove' +import LoanRepay, { + LoanRepayFromCollateralTab, + LoanRepayFromWalletTab, +} from '@/lend/components/PageLoanManage/LoanRepay' +import LoanSelfLiquidation from '@/lend/components/PageLoanManage/LoanSelfLiquidation' +import { type MarketUrlParams, PageContentProps } from '@/lend/types/lend.types' +import { useManageLoanMuiForm } from '@ui-kit/hooks/useFeatureFlags' +import { t } from '@ui-kit/lib/i18n' +import { type FormTab, FormTabs } from '@ui-kit/shared/ui/FormTabs/FormTabs' + +type ManageLoanProps = PageContentProps + +export const LendManageLegacyMenu = [ + { + value: 'loan', + label: t`Borrow`, + subTabs: [ + { value: 'loan-increase', label: t`Borrow more`, component: LoanBorrowMore }, + { value: 'loan-decrease', label: t`Repay`, component: LoanRepay }, + { value: 'loan-liquidate', label: t`Self-liquidate`, component: LoanSelfLiquidation }, + ], + }, + { + value: 'collateral', + label: t`Borrow`, + subTabs: [ + { value: 'collateral-increase', label: t`Add collateral`, component: LoanCollateralAdd }, + { value: 'collateral-decrease', label: t`Remove collateral`, component: LoanCollateralRemove }, + ], + }, + { + value: 'leverage', + label: t`Leverage`, + enabled: ({ market }) => market?.leverage?.hasLeverage(), + component: LoanBorrowMore, + }, +] satisfies FormTab[] + +export const LendManageNewMenu = [ + { + value: 'borrow', + label: ({ market }) => (market?.leverage?.hasLeverage() ? t`Leverage` : t`Borrow`), + component: LoanBorrowMoreWrapped, + }, + { + value: 'repay', + label: t`Repay`, + subTabs: [ + { value: 'from-wallet', label: t`From wallet`, component: LoanRepayFromWalletTab }, + { value: 'from-collateral', label: t`From collateral`, component: LoanRepayFromCollateralTab }, + ], + }, + { + value: 'collateral', + label: t`Collateral`, + subTabs: [ + { value: 'add', label: t`Add`, component: LoanAddCollateralTab }, + { value: 'remove', label: t`Remove`, component: LoanRemoveCollateralTab }, + ], + }, + { + value: 'soft-liquidation', + label: t`Manage soft liquidation`, + component: LoanSelfLiquidation, // todo: migrate `ManageSoftLiquidation` component + // subTabs: [ + // { value: 'improve-health', label: t`Improve health` }, + // { value: 'recover', label: t`Recover` }, + // { value: 'close-position', label: t`Close position` }, + // ], + }, +] satisfies FormTab[] + +export const ManageLoanTabs = (pageProps: ManageLoanProps) => { + const shouldUseManageLoanMuiForm = useManageLoanMuiForm() + return ( + + params={pageProps} + menu={shouldUseManageLoanMuiForm ? LendManageNewMenu : LendManageLegacyMenu} + shouldWrap={!shouldUseManageLoanMuiForm} + defaultTab={pageProps.rFormType} + /> + ) +} diff --git a/apps/main/src/lend/components/PageLoanManage/Page.tsx b/apps/main/src/lend/components/PageLoanManage/Page.tsx index 33e06b16c3..532e190864 100644 --- a/apps/main/src/lend/components/PageLoanManage/Page.tsx +++ b/apps/main/src/lend/components/PageLoanManage/Page.tsx @@ -4,7 +4,7 @@ import CampaignRewardsBanner from '@/lend/components/CampaignRewardsBanner' import ChartOhlcWrapper from '@/lend/components/ChartOhlcWrapper' import { MarketInformationComp } from '@/lend/components/MarketInformationComp' import { MarketInformationTabs } from '@/lend/components/MarketInformationTabs' -import LoanMange from '@/lend/components/PageLoanManage/index' +import { ManageLoanTabs } from '@/lend/components/PageLoanManage/ManageLoanTabs' import type { DetailInfoTypes } from '@/lend/components/PageLoanManage/types' import { useOneWayMarket } from '@/lend/entities/chain' import { useBorrowPositionDetails } from '@/lend/hooks/useBorrowPositionDetails' @@ -187,7 +187,7 @@ const Page = () => { (isManageSoftLiq ? ( ) : ( - + ))} diff --git a/apps/main/src/lend/components/PageLoanManage/index.tsx b/apps/main/src/lend/components/PageLoanManage/index.tsx deleted file mode 100644 index 6fbdbfb48c..0000000000 --- a/apps/main/src/lend/components/PageLoanManage/index.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import { useEffect, useMemo, useState } from 'react' -import LoanBorrowMore from '@/lend/components/PageLoanManage/LoanBorrowMore' -import LoanCollateralAdd from '@/lend/components/PageLoanManage/LoanCollateralAdd' -import LoanCollateralRemove from '@/lend/components/PageLoanManage/LoanCollateralRemove' -import LoanRepay from '@/lend/components/PageLoanManage/LoanRepay' -import LoanSelfLiquidation from '@/lend/components/PageLoanManage/LoanSelfLiquidation' -import type { CollateralFormType, LeverageFormType, LoanFormType } from '@/lend/components/PageLoanManage/types' -import networks from '@/lend/networks' -import { type MarketUrlParams, PageContentProps } from '@/lend/types/lend.types' -import { getLoanManagePathname } from '@/lend/utils/utilsRouter' -import { AddCollateralForm } from '@/llamalend/features/manage-loan/components/AddCollateralForm' -import { RemoveCollateralForm } from '@/llamalend/features/manage-loan/components/RemoveCollateralForm' -import { RepayForm } from '@/llamalend/features/manage-loan/components/RepayForm' -import Stack from '@mui/material/Stack' -import { AppFormContentWrapper } from '@ui/AppForm' -import { useNavigate } from '@ui-kit/hooks/router' -import { useManageLoanMuiForm } from '@ui-kit/hooks/useFeatureFlags' -import { t } from '@ui-kit/lib/i18n' -import { type TabOption, TabsSwitcher } from '@ui-kit/shared/ui/TabsSwitcher' -import { SizesAndSpaces } from '@ui-kit/themes/design/1_sizes_spaces' - -const { MaxWidth } = SizesAndSpaces - -const tabsLoan: TabOption[] = [ - { value: 'loan-increase', label: t`Borrow more` }, - { value: 'loan-decrease', label: t`Repay` }, - { value: 'loan-liquidate', label: t`Self-liquidate` }, -] - -const tabsCollateral: TabOption[] = [ - { value: 'collateral-increase', label: t`Add collateral` }, - { value: 'collateral-decrease', label: t`Remove collateral` }, -] - -const ManageLoan = (pageProps: PageContentProps & { params: MarketUrlParams }) => { - const { rChainId, rOwmId, rFormType, market, params, isLoaded } = pageProps - const push = useNavigate() - const shouldUseManageLoanMuiForm = useManageLoanMuiForm() - const useMuiForm = shouldUseManageLoanMuiForm && !!market - - type Tab = 'loan' | 'collateral' | 'leverage' - const tabs: TabOption[] = useMemo( - () => [ - { value: 'loan' as const, label: t`Loan` }, - { value: 'collateral' as const, label: t`Collateral` }, - ...(market?.leverage?.hasLeverage() ? [{ value: 'leverage' as const, label: t`Leverage` }] : []), - ], - [market?.leverage], - ) - - type SubTab = LoanFormType | CollateralFormType | LeverageFormType - const [subTab, setSubTab] = useState('loan-increase') - - const subTabs = useMemo( - () => (!rFormType || rFormType === 'loan' ? tabsLoan : rFormType === 'collateral' ? tabsCollateral : []), - [rFormType], - ) - - useEffect(() => setSubTab(subTabs[0]?.value), [subTabs]) - - return ( - - push(getLoanManagePathname(params, rOwmId, key))} - options={tabs} - /> - {useMuiForm ? ( - <> - - - {subTab === 'loan-increase' && ( - t.design.Layer[1].Fill }}> - - - - - )} - {subTab === 'loan-decrease' && market && ( - {}} - /> - )} - {subTab === 'loan-liquidate' && } - {subTab === 'collateral-increase' && market && ( - {}} - /> - )} - {subTab === 'collateral-decrease' && market && ( - {}} - /> - )} - {/** Leverage has no subtabs */} - {rFormType === 'leverage' && ( - t.design.Layer[1].Fill }}> - - - - - )} - - ) : ( - t.design.Layer[1].Fill }}> - - - - {subTab === 'loan-increase' && } - {subTab === 'loan-decrease' && } - {subTab === 'loan-liquidate' && } - {subTab === 'collateral-increase' && } - {subTab === 'collateral-decrease' && } - {/** Leverage has no subtabs */} - {rFormType === 'leverage' && } - - - )} - - ) -} - -export default ManageLoan diff --git a/apps/main/src/lend/types/lend.types.ts b/apps/main/src/lend/types/lend.types.ts index 0eae98be6a..12656357ba 100644 --- a/apps/main/src/lend/types/lend.types.ts +++ b/apps/main/src/lend/types/lend.types.ts @@ -84,8 +84,8 @@ export type VaultWithdrawFormType = 'withdraw' | 'unstake' | 'claim' export type VaultManageFormType = 'loan' | 'collateral' export type RFormType = VaultCreateFormType | VaultDepositFormType | VaultWithdrawFormType | VaultManageFormType | '' -export type PageContentProps = { - params: UrlParams +export type PageContentProps = { + params: T rChainId: ChainId rOwmId: string rFormType: RFormType diff --git a/apps/main/src/llamalend/features/manage-loan/components/AddCollateralForm.tsx b/apps/main/src/llamalend/features/manage-loan/components/AddCollateralForm.tsx index e220cdcd39..2b7996d65b 100644 --- a/apps/main/src/llamalend/features/manage-loan/components/AddCollateralForm.tsx +++ b/apps/main/src/llamalend/features/manage-loan/components/AddCollateralForm.tsx @@ -25,7 +25,7 @@ export const AddCollateralForm = ({ networks: NetworkDict chainId: ChainId enabled?: boolean - onAdded: NonNullable + onAdded?: NonNullable }) => { const network = networks[chainId] const [isOpen, , , toggle] = useSwitch(false) diff --git a/apps/main/src/llamalend/features/manage-loan/components/RemoveCollateralForm.tsx b/apps/main/src/llamalend/features/manage-loan/components/RemoveCollateralForm.tsx index 627257bccf..9041ad73ab 100644 --- a/apps/main/src/llamalend/features/manage-loan/components/RemoveCollateralForm.tsx +++ b/apps/main/src/llamalend/features/manage-loan/components/RemoveCollateralForm.tsx @@ -27,7 +27,7 @@ export const RemoveCollateralForm = ({ networks: NetworkDict chainId: ChainId enabled?: boolean - onRemoved: NonNullable + onRemoved?: NonNullable }) => { const network = networks[chainId] const [isOpen, , , toggle] = useSwitch(false) diff --git a/apps/main/src/llamalend/features/manage-loan/components/RepayForm.tsx b/apps/main/src/llamalend/features/manage-loan/components/RepayForm.tsx index 3bad68091c..7a9f1ee418 100644 --- a/apps/main/src/llamalend/features/manage-loan/components/RepayForm.tsx +++ b/apps/main/src/llamalend/features/manage-loan/components/RepayForm.tsx @@ -21,12 +21,18 @@ export const RepayForm = ({ chainId, enabled, onRepaid, + fromCollateral, + fromWallet, + fromBorrowed, }: { market: LlamaMarketTemplate | undefined networks: NetworkDict chainId: ChainId enabled?: boolean - onRepaid: NonNullable + onRepaid?: NonNullable + fromCollateral?: boolean + fromWallet?: boolean + fromBorrowed?: boolean }) => { const network = networks[chainId] const [isOpen, , , toggle] = useSwitch(false) @@ -86,33 +92,39 @@ export const RepayForm = ({ } > }> - - - + {fromCollateral && ( + + )} + {fromWallet && ( + + )} + {fromBorrowed && ( + + )}