Skip to content

Commit

Permalink
Add tooltips, improve spacing in summary and attempt to charge margin…
Browse files Browse the repository at this point in the history
… on interest
  • Loading branch information
sophialittlejohn committed Aug 8, 2024
1 parent 2708d04 commit c9d9a7f
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 53 deletions.
8 changes: 8 additions & 0 deletions centrifuge-app/src/components/Tooltips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,14 @@ export const tooltipText = {
label: 'Additional amount',
body: 'This can be used to repay an additional amount beyond the outstanding principal and interest of the asset. This will lead to an increase in the NAV of the pool.',
},
repayFormAvailableBalance: {
label: 'Available balance',
body: 'Balance of the asset originator account on Centrifuge.',
},
repayFormAvailableBalanceUnlimited: {
label: 'Available balance',
body: 'Unlimited because this is a virtual accounting process.',
},
}

export type TooltipsProps = {
Expand Down
43 changes: 18 additions & 25 deletions centrifuge-app/src/pages/Loan/ExternalRepayForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
useCentrifugeUtils,
wrapProxyCallsForAccount,
} from '@centrifuge/centrifuge-react'
import { Box, Button, CurrencyInput, InlineFeedback, Shelf, Stack, Text, Tooltip } from '@centrifuge/fabric'
import { Box, Button, CurrencyInput, InlineFeedback, Shelf, Stack, Text } from '@centrifuge/fabric'
import { BN } from 'bn.js'
import Decimal from 'decimal.js-light'
import { Field, FieldProps, Form, FormikProvider, useFormik } from 'formik'
Expand Down Expand Up @@ -282,35 +282,28 @@ export function ExternalRepayForm({ loan, destination }: { loan: ExternalLoan; d
)}

<Stack p={2} maxWidth="444px" bg="backgroundTertiary" gap={2} mt={2}>
<Text variant="heading4">Transaction summary</Text>
<Shelf justifyContent="space-between">
<Text variant="label2" color="textPrimary">
Available balance
</Text>
<Text variant="label2">
<Tooltip
body={
maxAvailable === UNLIMITED
? 'Unlimited because this is a virtual accounting process.'
: 'Balance of the asset originator account on Centrifuge'
}
style={{ pointerEvents: 'auto' }}
>
{maxAvailable === UNLIMITED ? 'No limit' : formatBalance(maxAvailable, displayCurrency, 2)}
</Tooltip>
</Text>
</Shelf>

<Stack gap={1}>
<Text variant="heading4">Transaction summary</Text>
<Shelf justifyContent="space-between">
<Text variant="label2" color="textPrimary">
Sale amount
<Tooltips
type={maxAvailable === UNLIMITED ? 'repayFormAvailableBalanceUnlimited' : 'repayFormAvailableBalance'}
/>
<Text variant="label2">
{maxAvailable === UNLIMITED ? 'No limit' : formatBalance(maxAvailable, displayCurrency, 2)}
</Text>
<Text variant="label2">{formatBalance(totalRepay, displayCurrency, 2)}</Text>
</Shelf>
</Stack>

{poolFees.renderSummary()}
<Stack gap={1}>
<Shelf justifyContent="space-between">
<Text variant="label2" color="textPrimary">
Sale amount
</Text>
<Text variant="label2">{formatBalance(totalRepay, displayCurrency, 2)}</Text>
</Shelf>
</Stack>

{poolFees.renderSummary()}
</Stack>

{destination === 'reserve' ? (
<InlineFeedback status="default">
Expand Down
90 changes: 62 additions & 28 deletions centrifuge-app/src/pages/Loan/RepayForm.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import { ActiveLoan, CreatedLoan, CurrencyBalance, ExternalLoan, findBalance, Loan } from '@centrifuge/centrifuge-js'
import {
ActiveLoan,
CreatedLoan,
CurrencyBalance,
ExternalLoan,
findBalance,
Loan,
Rate,
} from '@centrifuge/centrifuge-js'
import {
useBalances,
useCentrifugeApi,
useCentrifugeTransaction,
useCentrifugeUtils,
wrapProxyCallsForAccount,
} from '@centrifuge/centrifuge-react'
import { Box, Button, CurrencyInput, InlineFeedback, Select, Shelf, Stack, Text, Tooltip } from '@centrifuge/fabric'
import { Box, Button, CurrencyInput, InlineFeedback, Select, Shelf, Stack, Text } from '@centrifuge/fabric'
import Decimal from 'decimal.js-light'
import { Field, FieldProps, Form, FormikProvider, useFormik } from 'formik'
import * as React from 'react'
Expand Down Expand Up @@ -75,6 +83,7 @@ function InternalRepayForm({ loan, destination }: { loan: ActiveLoan | CreatedLo
const destinationLoan = loans?.find((l) => l.id === destination) as Loan
const displayCurrency = destination === 'reserve' ? pool.currency.symbol : 'USD'
const utils = useCentrifugeUtils()
const [usedMaxInterest, setUsedMaxInterest] = React.useState(false)

const { execute: doRepayTransaction, isLoading: isRepayLoading } = useCentrifugeTransaction(
isCashLoan(loan) ? 'Withdraw funds' : 'Repay asset',
Expand Down Expand Up @@ -127,10 +136,37 @@ function InternalRepayForm({ loan, destination }: { loan: ActiveLoan | CreatedLo
category: 'correction',
},
onSubmit: (values, actions) => {
const interest = CurrencyBalance.fromFloat(values.interest || 0, pool.currency.decimals)
let interest = CurrencyBalance.fromFloat(values.interest || 0, pool.currency.decimals)
const additionalAmount = CurrencyBalance.fromFloat(values.amountAdditional || 0, pool.currency.decimals)
const principal = CurrencyBalance.fromFloat(values.principal || 0, pool.currency.decimals)

if (usedMaxInterest) {
const time = Date.now() - loan.fetchedAt.getTime()
const outstandingInterest =
'outstandingInterest' in loan
? loan.outstandingInterest
: CurrencyBalance.fromFloat(0, pool.currency.decimals)
const outstandingPrincipal = new CurrencyBalance(
loan.outstandingDebt.sub(outstandingInterest),
pool.currency.decimals
)

// TODO: this number is way too small, after repaying we still end up with interest outstanding
const mostUpToDateInterest = CurrencyBalance.fromFloat(
outstandingPrincipal
.toDecimal()
.mul(Rate.fractionFromAprPercent(loan.pricing.interestRate.toDecimal().mul(100)).toDecimal())
.mul(time / (60 * 60 * 24 * 365))
.add(outstandingInterest.toDecimal()),
pool.currency.decimals
)
interest = mostUpToDateInterest
console.log(
`Repaying with the most up to date outstanding interest: ${mostUpToDateInterest.toDecimal()} instead of ${outstandingInterest.toDecimal()}`,
loan.pricing.interestRate.toDecimal().toString()
)
}

doRepayTransaction([principal, interest, additionalAmount], {
account,
forceProxyType: 'Borrow',
Expand Down Expand Up @@ -193,7 +229,9 @@ function InternalRepayForm({ loan, destination }: { loan: ActiveLoan | CreatedLo
disabled={isRepayLoading}
currency={displayCurrency}
onChange={(value) => form.setFieldValue('principal', value)}
onSetMax={() => form.setFieldValue('principal', maxPrincipal.gte(0) ? maxPrincipal : 0)}
onSetMax={() => {
form.setFieldValue('principal', maxPrincipal.gte(0) ? maxPrincipal : 0)
}}
secondaryLabel={`${formatBalance(maxPrincipal, displayCurrency)} outstanding`}
/>
)
Expand All @@ -217,7 +255,10 @@ function InternalRepayForm({ loan, destination }: { loan: ActiveLoan | CreatedLo
disabled={isRepayLoading}
currency={displayCurrency}
onChange={(value) => form.setFieldValue('interest', value)}
onSetMax={() => form.setFieldValue('interest', maxInterest.gte(0) ? maxInterest : 0)}
onSetMax={() => {
setUsedMaxInterest(true)
form.setFieldValue('interest', maxInterest.gte(0) ? maxInterest : 0)
}}
/>
)
}}
Expand Down Expand Up @@ -300,34 +341,27 @@ function InternalRepayForm({ loan, destination }: { loan: ActiveLoan | CreatedLo

<Stack p={2} maxWidth="444px" bg="backgroundTertiary" gap={2} mt={2}>
<Text variant="heading4">Transaction summary</Text>
<Shelf justifyContent="space-between">
<Text variant="label2" color="textPrimary">
Available balance
</Text>
<Text variant="label2">
<Tooltip
body={
maxAvailable === UNLIMITED
? 'Unlimited because this is a virtual accounting process.'
: 'Balance of the asset originator account on Centrifuge'
}
style={{ pointerEvents: 'auto' }}
>
{maxAvailable === UNLIMITED ? 'No limit' : formatBalance(maxAvailable, displayCurrency, 2)}
</Tooltip>
</Text>
</Shelf>

<Stack gap={1}>
<Shelf justifyContent="space-between">
<Text variant="label2" color="textPrimary">
{isCashLoan(loan) ? 'Withdrawal amount' : 'Repayment amount'}
<Tooltips
type={maxAvailable === UNLIMITED ? 'repayFormAvailableBalanceUnlimited' : 'repayFormAvailableBalance'}
/>
<Text variant="label2">
{maxAvailable === UNLIMITED ? 'No limit' : formatBalance(maxAvailable, displayCurrency, 2)}
</Text>
<Text variant="label2">{formatBalance(totalRepay, displayCurrency, 2)}</Text>
</Shelf>
</Stack>

{poolFees.renderSummary()}
<Stack gap={1}>
<Shelf justifyContent="space-between">
<Text variant="label2" color="textPrimary">
{isCashLoan(loan) ? 'Withdrawal amount' : 'Repayment amount'}
</Text>
<Text variant="label2">{formatBalance(totalRepay, displayCurrency, 2)}</Text>
</Shelf>
</Stack>

{poolFees.renderSummary()}
</Stack>

{destination === 'reserve' ? (
<InlineFeedback status="default">
Expand Down

0 comments on commit c9d9a7f

Please sign in to comment.