diff --git a/src/components/CryptoAmountSelector.tsx b/src/components/CryptoAmountSelector.tsx index df7fe0b..9d927a2 100644 --- a/src/components/CryptoAmountSelector.tsx +++ b/src/components/CryptoAmountSelector.tsx @@ -87,7 +87,7 @@ export const CryptoAmountSelector = ({ /> )} - {valueCents ? `≈ ${formatCentAmount(valueCents)}` : null} + {valueCents ? `≈ ${formatCentAmount(valueCents)}` : null} diff --git a/src/components/LoansModal/LoansModal.tsx b/src/components/LoansModal/LoansModal.tsx index e8ff8f9..d9502b8 100644 --- a/src/components/LoansModal/LoansModal.tsx +++ b/src/components/LoansModal/LoansModal.tsx @@ -1,10 +1,7 @@ -import { Success } from '@components/Alert'; -import { CircleButton } from '@components/Button'; +import { Dialog } from '@components/Dialog'; import type { Loan } from '@contexts/loan-context'; -import type { SupportedCurrency } from 'currencies'; import { isNil } from 'ramda'; import { useState } from 'react'; -import { IoClose as CloseIcon } from 'react-icons/io5'; import LoansView from './LoansView'; import RepayView from './RepayView'; @@ -13,99 +10,29 @@ export interface LoansModalProps { onClose: () => void; } -type RepayAlert = - | { - kind: 'success'; - ticker: SupportedCurrency; - amount: string; - } - | { - kind: 'full-success'; - ticker: SupportedCurrency; - }; - const LoansModal = ({ modalId, onClose }: LoansModalProps) => { const [selectedLoan, setSelectedLoan] = useState(null); - const [alert, setAlert] = useState(null); const handleBackClicked = () => setSelectedLoan(null); const handleClose = () => { setSelectedLoan(null); - setAlert(null); onClose(); }; - const handleRepaySuccess = (ticker: SupportedCurrency, amount: string) => { - setSelectedLoan(null); - setAlert({ kind: 'success', ticker, amount }); - }; - - const handleRepayFullSuccess = (ticker: SupportedCurrency) => { - setSelectedLoan(null); - setAlert({ kind: 'full-success', ticker }); - }; - - const handleAlertClose = () => setAlert(null); - const handleRepayClicked = (loan: Loan) => { - setAlert(null); setSelectedLoan(loan); }; return ( - -
- {alert && alert.kind === 'success' ? ( - - ) : null} - {alert && alert.kind === 'full-success' ? ( - - ) : null} - {isNil(selectedLoan) ? ( - - ) : ( - - )} -
-
- -
-
+ + {isNil(selectedLoan) ? ( + + ) : ( + + )} + ); }; -type RepaySuccessAlertProps = { - ticker: SupportedCurrency; - amount: string; - onClose: () => void; -}; - -const RepaySuccessAlert = ({ ticker, amount, onClose }: RepaySuccessAlertProps) => ( - - - Successfully repaid {amount} {ticker} - - - - - -); - -const FullRepaySuccessAlert = ({ ticker, onClose }: { ticker: SupportedCurrency; onClose: VoidFunction }) => ( - - Successfully repaid all of the borrowed {ticker} - - - - -); - export default LoansModal; diff --git a/src/components/LoansModal/RepayView.tsx b/src/components/LoansModal/RepayView.tsx index 7495e97..df9c22c 100644 --- a/src/components/LoansModal/RepayView.tsx +++ b/src/components/LoansModal/RepayView.tsx @@ -1,45 +1,42 @@ import { Button } from '@components/Button'; import { CryptoAmountSelector } from '@components/CryptoAmountSelector'; -import { Loading } from '@components/Loading'; +import { ErrorDialogContent, LoadingDialogContent, SuccessDialogContent } from '@components/Dialog'; import { type Loan, useLoans } from '@contexts/loan-context'; import { usePools } from '@contexts/pool-context'; import { useWallet } from '@contexts/wallet-context'; import { contractClient as loanManagerClient } from '@contracts/loan_manager'; -import { SCALAR_7, formatAPR, formatAmount, toCents } from '@lib/formatting'; -import type { SupportedCurrency } from 'currencies'; -import { type ChangeEvent, useState } from 'react'; +import { formatAPR, formatAmount, toCents } from '@lib/formatting'; +import { useState } from 'react'; import { CURRENCY_BINDINGS } from 'src/currency-bindings'; interface RepayViewProps { loan: Loan; - onBack: () => void; - onSuccess: (ticker: SupportedCurrency, amount: string) => void; - onFullSuccess: (ticker: SupportedCurrency) => void; + onBack: VoidFunction; } -const RepayView = ({ loan, onBack, onSuccess, onFullSuccess }: RepayViewProps) => { +const RepayView = ({ loan, onBack }: RepayViewProps) => { const { borrowedAmount, borrowedTicker, collateralAmount, collateralTicker, unpaidInterest } = loan; const { name } = CURRENCY_BINDINGS[borrowedTicker]; const { wallet, signTransaction, refetchBalances } = useWallet(); const { prices, pools } = usePools(); const { refetchLoans } = useLoans(); - const [amount, setAmount] = useState('0'); + const [amount, setAmount] = useState(0n); const [isRepaying, setIsRepaying] = useState(false); const [isRepayingAll, setIsRepayingAll] = useState(false); + const [success, setSuccess] = useState<'PARTIAL_REPAY_SUCCESS' | 'FULL_REPAY_SUCCESS' | null>(null); + const [error, setError] = useState(null); const loanBalance = borrowedAmount + unpaidInterest; const apr = pools?.[borrowedTicker]?.annualInterestRate; const price = prices?.[borrowedTicker]; - const valueCents = price ? toCents(price, BigInt(amount) * SCALAR_7) : undefined; + const valueCents = price ? toCents(price, amount) : undefined; - const max = (loanBalance / SCALAR_7).toString(); - - const handleAmountChange = (ev: ChangeEvent) => { - setAmount(ev.target.value); + const handleAmountChange = (stroops: bigint) => { + setAmount(stroops); }; const handleSelectMax = () => { - setAmount(max); + setAmount(loanBalance); }; const handleRepayClick = async () => { @@ -47,13 +44,13 @@ const RepayView = ({ loan, onBack, onSuccess, onFullSuccess }: RepayViewProps) = setIsRepaying(true); - const tx = await loanManagerClient.repay({ user: wallet.address, amount: BigInt(amount) * SCALAR_7 }); + const tx = await loanManagerClient.repay({ user: wallet.address, amount }); try { await tx.signAndSend({ signTransaction }); - onSuccess(borrowedTicker, amount); + setSuccess('PARTIAL_REPAY_SUCCESS'); } catch (err) { console.error('Error repaying', err); - alert('Error repaying'); + setError(err as Error); } refetchLoans(); refetchBalances(); @@ -68,22 +65,57 @@ const RepayView = ({ loan, onBack, onSuccess, onFullSuccess }: RepayViewProps) = const tx = await loanManagerClient.repay_and_close_manager({ user: wallet.address, // +5% to liabilities. TEMPORARY hard-coded solution for max allowance. - max_allowed_amount: (BigInt(loanBalance) * BigInt(5)) / BigInt(100) + BigInt(loanBalance), + max_allowed_amount: (loanBalance * 5n) / 100n + loanBalance, }); try { await tx.signAndSend({ signTransaction }); - onFullSuccess(borrowedTicker); + setSuccess('FULL_REPAY_SUCCESS'); } catch (err) { console.error('Error repaying', err); - alert('Error repaying'); + setError(err as Error); } refetchLoans(); refetchBalances(); setIsRepayingAll(false); }; + if (isRepaying) { + return ( + + ); + } + + if (isRepayingAll) { + return ( + + ); + } + + if (success) { + const subtitle = + success === 'FULL_REPAY_SUCCESS' + ? `Successfully repaid all of your loan. The collateral ${formatAmount(collateralAmount)} ${collateralTicker} was returned back to your wallet.` + : `Successfully repaid ${formatAmount(amount)} ${borrowedTicker}.`; + + return ; + } + + if (error) { + return ; + } + return ( - <> +

Repay {name}

Repay some or all of your loan. Repaying the loan in full will return the collateral back to you. @@ -97,7 +129,7 @@ const RepayView = ({ loan, onBack, onSuccess, onFullSuccess }: RepayViewProps) =

Select the amount to repay

Back - {!isRepaying ? ( - - ) : ( - - )} - {!isRepayingAll ? ( - - ) : ( - - )} + +
- + ); }; -const LoadingButton = () => ( - -); - export default RepayView;