Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 83 additions & 18 deletions apps/main/src/lend/components/PageLoanManage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ import LoanCollateralRemove from '@/lend/components/PageLoanManage/LoanCollatera
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'
Expand All @@ -28,8 +33,10 @@ const tabsCollateral: TabOption<CollateralFormType>[] = [
]

const ManageLoan = (pageProps: PageContentProps & { params: MarketUrlParams }) => {
const { rOwmId, rFormType, market, params } = pageProps
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<Tab>[] = useMemo(
Expand Down Expand Up @@ -65,26 +72,84 @@ const ManageLoan = (pageProps: PageContentProps & { params: MarketUrlParams }) =
onChange={(key) => push(getLoanManagePathname(params, rOwmId, key))}
options={tabs}
/>
<Stack sx={{ backgroundColor: (t) => t.design.Layer[1].Fill }}>
<TabsSwitcher
variant="underlined"
size="small"
value={subTab}
onChange={setSubTab}
options={subTabs}
fullWidth
/>
{useMuiForm ? (
<>
<TabsSwitcher
variant="underlined"
size="small"
value={subTab}
onChange={setSubTab}
options={subTabs}
fullWidth
/>

<AppFormContentWrapper>
{subTab === 'loan-increase' && <LoanBorrowMore {...pageProps} />}
{subTab === 'loan-decrease' && <LoanRepay {...pageProps} />}
{subTab === 'loan-increase' && (
<Stack sx={{ backgroundColor: (t) => t.design.Layer[1].Fill }}>
<AppFormContentWrapper>
<LoanBorrowMore {...pageProps} />
</AppFormContentWrapper>
</Stack>
)}
{subTab === 'loan-decrease' && market && (
<RepayForm
networks={networks}
chainId={rChainId}
market={market}
enabled={isLoaded}
// No extra side effects required for legacy store; llamalend hooks handle cache invalidation.
onRepaid={async () => {}}
/>
)}
{subTab === 'loan-liquidate' && <LoanSelfLiquidation {...pageProps} />}
{subTab === 'collateral-increase' && <LoanCollateralAdd {...pageProps} />}
{subTab === 'collateral-decrease' && <LoanCollateralRemove {...pageProps} />}
{subTab === 'collateral-increase' && market && (
<AddCollateralForm
networks={networks}
chainId={rChainId}
market={market}
enabled={isLoaded}
onAdded={async () => {}}
/>
)}
{subTab === 'collateral-decrease' && market && (
<RemoveCollateralForm
networks={networks}
chainId={rChainId}
market={market}
enabled={isLoaded}
onRemoved={async () => {}}
/>
)}
{/** Leverage has no subtabs */}
{rFormType === 'leverage' && <LoanBorrowMore isLeverage {...pageProps} />}
</AppFormContentWrapper>
</Stack>
{rFormType === 'leverage' && (
<Stack sx={{ backgroundColor: (t) => t.design.Layer[1].Fill }}>
<AppFormContentWrapper>
<LoanBorrowMore isLeverage {...pageProps} />
</AppFormContentWrapper>
</Stack>
)}
</>
) : (
<Stack sx={{ backgroundColor: (t) => t.design.Layer[1].Fill }}>
<TabsSwitcher
variant="underlined"
size="small"
value={subTab}
onChange={setSubTab}
options={subTabs}
fullWidth
/>

<AppFormContentWrapper>
{subTab === 'loan-increase' && <LoanBorrowMore {...pageProps} />}
{subTab === 'loan-decrease' && <LoanRepay {...pageProps} />}
{subTab === 'loan-liquidate' && <LoanSelfLiquidation {...pageProps} />}
{subTab === 'collateral-increase' && <LoanCollateralAdd {...pageProps} />}
{subTab === 'collateral-decrease' && <LoanCollateralRemove {...pageProps} />}
{/** Leverage has no subtabs */}
{rFormType === 'leverage' && <LoanBorrowMore isLeverage {...pageProps} />}
</AppFormContentWrapper>
</Stack>
)}
</Stack>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import Stack from '@mui/material/Stack'
import { useBorrowPreset } from '@ui-kit/hooks/useLocalStorage'
import { t } from '@ui-kit/lib/i18n'
import { InputDivider } from '../../../widgets/InputDivider'
import { useCreateLoanForm } from '../hooks/useCreateLoanForm'
import { setValueOptions } from '../react-form.utils'
import { type BorrowFormExternalFields, type OnBorrowFormUpdate } from '../types'
import { useBorrowForm } from '../useBorrowForm'
import { AdvancedBorrowOptions } from './AdvancedBorrowOptions'
import { CreateLoanInfoAccordion } from './CreateLoanInfoAccordion'
import { LeverageInput } from './LeverageInput'
Expand Down Expand Up @@ -70,7 +70,7 @@ export const CreateLoanForm = <ChainId extends IChainId>({
formErrors,
tooMuchDebt,
isApproved,
} = useBorrowForm({ market, network, preset, onCreated })
} = useCreateLoanForm({ market, network, preset, onCreated })
const setRange = useCallback((range: number) => form.setValue('range', range, setValueOptions), [form])
useFormSync(values, onUpdate)

Expand All @@ -97,25 +97,19 @@ export const CreateLoanForm = <ChainId extends IChainId>({
blockchainId={network.id}
name="userCollateral"
form={form}
isLoading={maxTokenValues.isCollateralLoading}
isError={maxTokenValues.isCollateralError}
max={values.maxCollateral}
max={{ ...maxTokenValues.collateral, fieldName: 'maxCollateral' }}
testId="borrow-collateral-input"
network={network}
maxFieldName="maxCollateral"
/>
<LoanFormTokenInput
label={t`Borrow`}
token={borrowToken}
blockchainId={network.id}
name="debt"
form={form}
isLoading={maxTokenValues.isDebtLoading}
isError={maxTokenValues.isDebtError}
max={values.maxDebt}
max={{ ...maxTokenValues.debt, fieldName: 'maxDebt' }}
testId="borrow-debt-input"
network={network}
maxFieldName="maxDebt"
message={
values.maxDebt && <FormMessage label={t`Max borrow:`} value={values.maxDebt} symbol={borrowToken?.symbol} />
}
Expand All @@ -124,12 +118,10 @@ export const CreateLoanForm = <ChainId extends IChainId>({

{market && hasLeverage(market) && (
<LeverageInput
leverageEnabled={values.leverageEnabled}
checked={values.leverageEnabled}
form={form}
params={params}
maxLeverage={maxTokenValues.maxLeverage}
isError={maxTokenValues.isLeverageError}
isLoading={maxTokenValues.isLeverageLoading}
/>
)}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type ChangeEvent, useCallback } from 'react'
import type { UseFormReturn } from 'react-hook-form'
import type { Query } from '@/llamalend/widgets/manage-loan/loan.types'
import Checkbox from '@mui/material/Checkbox'
import FormControlLabel from '@mui/material/FormControlLabel'
import Stack from '@mui/material/Stack'
Expand All @@ -17,18 +18,14 @@ const { Spacing } = SizesAndSpaces

export const LeverageInput = ({
form,
leverageEnabled,
checked,
params,
maxLeverage,
isError,
isLoading,
maxLeverage: { data: maxLeverage, error, isLoading },
}: {
leverageEnabled: boolean
checked: boolean
form: UseFormReturn<BorrowForm>
params: BorrowFormQueryParams
maxLeverage: Decimal | undefined
isError: boolean
isLoading: boolean
maxLeverage: Query<Decimal>
}) => {
const { leverage } = useCreateLoanExpectedCollateral(params).data ?? {}

Expand All @@ -44,7 +41,7 @@ export const LeverageInput = ({
<>
<Typography variant="headingXsBold">{t`Enable leverage`}</Typography>
<WithSkeleton loading={isLoading}>
<Typography {...(isError && { color: 'error.main' })} variant="bodyXsRegular">
<Typography {...(error && { color: 'error.main' })} variant="bodyXsRegular">
{t`up to ${formatNumber(maxLeverage, { maximumFractionDigits: 1 })}x 🔥`}
</Typography>
</WithSkeleton>
Expand All @@ -55,7 +52,7 @@ export const LeverageInput = ({
data-testid="leverage-checkbox"
size="small"
disabled={!maxLeverage}
checked={leverageEnabled}
checked={checked}
onChange={onLeverageChanged}
sx={{ padding: 0, paddingInlineEnd: Spacing.xs, alignSelf: 'start' }}
/>
Expand All @@ -64,9 +61,9 @@ export const LeverageInput = ({
<ActionInfo
label={t`Leverage`}
value={leverage == null ? '–' : `${formatNumber(leverage, { maximumFractionDigits: 2 })}x`}
valueColor={isError ? 'error' : undefined}
valueColor={error ? 'error' : undefined}
loading={isLoading}
error={isError}
error={error}
size="medium"
data-testid="leverage-value"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ import { useDebouncedValue } from '@ui-kit/hooks/useDebounce'
import { formDefaultOptions } from '@ui-kit/lib/model'
import { Decimal } from '@ui-kit/utils'
import { SLIPPAGE_PRESETS } from '@ui-kit/widgets/SlippageSettings/slippage.utils'
import { BORROW_PRESET_RANGES, BorrowPreset } from '../../constants'
import { type CreateLoanOptions, useCreateLoanMutation } from '../../mutations/create-loan.mutation'
import { useBorrowCreateLoanIsApproved } from '../../queries/create-loan/borrow-create-loan-approved.query'
import { borrowFormValidationSuite } from '../../queries/validation/borrow.validation'
import { useMaxTokenValues } from './hooks/useMaxTokenValues'
import { useFormErrors } from './react-form.utils'
import { type BorrowForm } from './types'
import { BORROW_PRESET_RANGES, BorrowPreset } from '../../../constants'
import { type CreateLoanOptions, useCreateLoanMutation } from '../../../mutations/create-loan.mutation'
import { useBorrowCreateLoanIsApproved } from '../../../queries/create-loan/borrow-create-loan-approved.query'
import { borrowFormValidationSuite } from '../../../queries/validation/borrow.validation'
import { useFormErrors } from '../react-form.utils'
import { type BorrowForm } from '../types'
import { useMaxTokenValues } from './useMaxTokenValues'

const useCallbackAfterFormUpdate = (form: UseFormReturn<BorrowForm>, callback: () => void) =>
useEffect(() => form.subscribe({ formState: { values: true }, callback }), [form, callback])

export function useBorrowForm<ChainId extends IChainId>({
export function useCreateLoanForm<ChainId extends IChainId>({
market,
network,
network: { chainId },
Expand Down
28 changes: 18 additions & 10 deletions apps/main/src/llamalend/features/borrow/hooks/useMaxTokenValues.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ export function useMaxTokenValues(
) {
const {
data: userBalance,
isError: isBalanceError,
error: balanceError,
isLoading: isBalanceLoading,
} = useTokenBalance(params, collateralToken)
const { data: maxBorrow, isError: isErrorMaxBorrow, isLoading: isLoadingMaxBorrow } = useCreateLoanMaxReceive(params)
const { data: maxBorrow, error: maxBorrowError, isLoading: isLoadingMaxBorrow } = useCreateLoanMaxReceive(params)
const {
data: maxTotalLeverage,
isError: isErrorMaxLeverage,
error: maxLeverageError,
isLoading: isLoadingMaxLeverage,
} = useMarketMaxLeverage(params)

Expand All @@ -46,12 +46,20 @@ export function useMaxTokenValues(
useEffect(() => form.setValue('maxCollateral', maxCollateral, setValueOptions), [form, maxCollateral])

return {
isCollateralLoading: !collateralToken || isLoadingMaxBorrow || isBalanceLoading,
isDebtLoading: !collateralToken || isLoadingMaxBorrow,
isCollateralError: isErrorMaxBorrow || isBalanceError,
isDebtError: isErrorMaxBorrow,
isLeverageError: isErrorMaxLeverage || isErrorMaxBorrow,
isLeverageLoading: isLoadingMaxLeverage || isLoadingMaxBorrow,
maxLeverage,
collateral: {
data: maxCollateral,
isLoading: !collateralToken || isLoadingMaxBorrow || isBalanceLoading,
error: maxBorrowError || balanceError,
},
debt: {
data: maxDebt,
isLoading: !collateralToken || isLoadingMaxBorrow,
error: maxBorrowError,
},
maxLeverage: {
data: maxLeverage,
isLoading: isLoadingMaxLeverage || isLoadingMaxBorrow,
error: maxLeverageError || maxBorrowError,
},
}
}
4 changes: 1 addition & 3 deletions apps/main/src/llamalend/features/borrow/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { MakeOptional } from '@ui-kit/types/util'
import { Decimal } from '@ui-kit/utils'

/** Complete borrow creation form with all fields already filled in (after validation) */
export type CompleteBorrowForm = {
type CompleteBorrowForm = {
userCollateral: Decimal
userBorrowed: Decimal // currently hidden and always 0
debt: Decimal
Expand All @@ -33,5 +33,3 @@ export type BorrowFormQueryParams<T = IChainId> = FieldsOf<BorrowFormQuery<T>>

/** A simple token representation */
export type Token = { symbol: string; address: Address }

export type BorrowFormErrors = (readonly [keyof BorrowForm | 'root', string])[]
Loading