diff --git a/centrifuge-app/src/components/Report/CashflowStatement.tsx b/centrifuge-app/src/components/Report/CashflowStatement.tsx index f2d20ab4da..56b100678d 100644 --- a/centrifuge-app/src/components/Report/CashflowStatement.tsx +++ b/centrifuge-app/src/components/Report/CashflowStatement.tsx @@ -202,37 +202,31 @@ export function CashflowStatement({ pool }: { pool: Pool }) { const netCashflowRecords: Row[] = React.useMemo(() => { return [ - ...(poolFeeStates - ?.map((poolFeeStateByPeriod) => { - return Object.values(poolFeeStateByPeriod) - ?.map((feeState) => { - // some fee data may be incomplete since fees may have been added sometime after pool creation - // this fill the nonexistant fee data with zero values - let missingStates: { - timestamp: string - sumPaidAmountByPeriod: CurrencyBalance - }[] = [] - if (feeState.length !== poolStates?.length) { - const missingTimestamps = poolStates - ?.map((state) => state.timestamp) - .filter((timestamp) => !feeState.find((state) => state.timestamp === timestamp)) - missingStates = - missingTimestamps?.map((timestamp) => { - return { - timestamp, - sumPaidAmountByPeriod: CurrencyBalance.fromFloat(0, pool.currency.decimals), - } - }) || [] - } + ...(Object.entries(poolFeeStates || {})?.flatMap(([, feeState]) => { + // some fee data may be incomplete since fees may have been added sometime after pool creation + // this fill the nonexistant fee data with zero values + let missingStates: { + timestamp: string + sumPaidAmountByPeriod: CurrencyBalance + }[] = [] + if (feeState.length !== poolStates?.length) { + const missingTimestamps = poolStates + ?.map((state) => state.timestamp) + .filter((timestamp) => !feeState.find((state) => state.timestamp.slice(0, 10) === timestamp.slice(0, 10))) + missingStates = + missingTimestamps?.map((timestamp) => { return { - name: feeState[0].poolFee.name, - value: [...missingStates, ...feeState].map((state) => state.sumPaidAmountByPeriod.toDecimal().neg()), - formatter: (v: any) => `${formatBalance(v, pool.currency.displayName, 2)}`, + timestamp, + sumPaidAmountByPeriod: CurrencyBalance.fromFloat(0, pool.currency.decimals), } - }) - .flat() - }) - .flat() || []), + }) || [] + } + return { + name: feeState[0].poolFee.name, + value: [...missingStates, ...feeState].map((state) => state.sumPaidAmountByPeriod.toDecimal().neg()), + formatter: (v: any) => `${formatBalance(v, pool.currency.displayName, 2)}`, + } + }) || []), { name: 'Net cash flow after fees', value: diff --git a/centrifuge-app/src/pages/Loan/ErrorMessage.tsx b/centrifuge-app/src/pages/Loan/ErrorMessage.tsx index d27bde3308..f5d21ec067 100644 --- a/centrifuge-app/src/pages/Loan/ErrorMessage.tsx +++ b/centrifuge-app/src/pages/Loan/ErrorMessage.tsx @@ -2,7 +2,7 @@ import { Box, InlineFeedback, Text } from '@centrifuge/fabric' type Props = { children: React.ReactNode - type: 'default' | 'critical' + type: 'default' | 'critical' | 'warning' condition: boolean } @@ -15,6 +15,10 @@ const styles: Record = { bg: 'statusCriticalBg', color: 'statusCritical', }, + warning: { + bg: 'statusWarningBg', + color: 'statusWarning', + }, } export function ErrorMessage({ children, condition, type }: Props) { diff --git a/centrifuge-app/src/pages/Loan/ExternalFinanceForm.tsx b/centrifuge-app/src/pages/Loan/ExternalFinanceForm.tsx index db070c8f54..d22c6951b9 100644 --- a/centrifuge-app/src/pages/Loan/ExternalFinanceForm.tsx +++ b/centrifuge-app/src/pages/Loan/ExternalFinanceForm.tsx @@ -102,6 +102,10 @@ export function ExternalFinanceForm({ loan, source }: { loan: ExternalLoan; sour validateOnMount: true, }) + React.useEffect(() => { + financeForm.validateForm() + }, [source]) + const financeFormRef = React.useRef(null) useFocusInvalidInput(financeForm, financeFormRef) @@ -109,7 +113,7 @@ export function ExternalFinanceForm({ loan, source }: { loan: ExternalLoan; sour const maxAvailable = source === 'reserve' ? pool.reserve.available.toDecimal() : sourceLoan.outstandingDebt.toDecimal() - const withdraw = useWithdraw(loan.poolId, account!, totalFinance) + const withdraw = useWithdraw(loan.poolId, account!, totalFinance, source) if (loan.status === 'Closed' || ('valuationMethod' in loan.pricing && loan.pricing.valuationMethod !== 'oracle')) { return null @@ -244,7 +248,10 @@ export function ExternalFinanceForm({ loan, source }: { loan: ExternalLoan; sour type="submit" loading={isFinanceLoading} disabled={ - !withdraw.isValid || !poolFees.isValid(financeForm) || !financeForm.isValid || maxAvailable.eq(0) + !withdraw.isValid(financeForm) || + !poolFees.isValid(financeForm) || + !financeForm.isValid || + maxAvailable.eq(0) } > Purchase diff --git a/centrifuge-app/src/pages/Loan/ExternalRepayForm.tsx b/centrifuge-app/src/pages/Loan/ExternalRepayForm.tsx index 975e2bd86a..b193b773a3 100644 --- a/centrifuge-app/src/pages/Loan/ExternalRepayForm.tsx +++ b/centrifuge-app/src/pages/Loan/ExternalRepayForm.tsx @@ -144,6 +144,10 @@ export function ExternalRepayForm({ loan, destination }: { loan: ExternalLoan; d validateOnMount: true, }) + React.useEffect(() => { + repayForm.validateForm() + }, [destination]) + const repayFormRef = React.useRef(null) useFocusInvalidInput(repayForm, repayFormRef) diff --git a/centrifuge-app/src/pages/Loan/FinanceForm.tsx b/centrifuge-app/src/pages/Loan/FinanceForm.tsx index ee8aa98546..4c2e69a321 100644 --- a/centrifuge-app/src/pages/Loan/FinanceForm.tsx +++ b/centrifuge-app/src/pages/Loan/FinanceForm.tsx @@ -161,10 +161,14 @@ function InternalFinanceForm({ loan, source }: { loan: LoanType; source: string validateOnMount: true, }) + React.useEffect(() => { + financeForm.validateForm() + }, [source]) + const financeFormRef = React.useRef(null) useFocusInvalidInput(financeForm, financeFormRef) - const withdraw = useWithdraw(loan.poolId, account!, Dec(financeForm.values.principal || 0)) + const withdraw = useWithdraw(loan.poolId, account!, Dec(financeForm.values.principal || 0), source) if (loan.status === 'Closed') { return null @@ -318,7 +322,7 @@ function InternalFinanceForm({ loan, source }: { loan: LoanType; source: string loading={isFinanceLoading} disabled={ !financeForm.values.principal || - !withdraw.isValid || + !withdraw.isValid(financeForm) || !poolFees.isValid(financeForm) || !financeForm.isValid || maxAvailable.eq(0) @@ -334,7 +338,7 @@ function InternalFinanceForm({ loan, source }: { loan: LoanType; source: string ) } -function WithdrawSelect({ withdrawAddresses }: { withdrawAddresses: WithdrawAddress[] }) { +function WithdrawSelect({ withdrawAddresses, poolId }: { withdrawAddresses: WithdrawAddress[]; poolId: string }) { const form = useFormikContext>() const utils = useCentrifugeUtils() const getName = useGetNetworkName() @@ -357,7 +361,15 @@ function WithdrawSelect({ withdrawAddresses }: { withdrawAddresses: WithdrawAddr // eslint-disable-next-line react-hooks/exhaustive-deps }, [withdrawAddresses.length]) - if (!withdrawAddresses.length) return null + if (!withdrawAddresses.length) + return ( + + + To purchase/finance this asset, the pool must set trusted withdrawal addresses to which funds will be sent. + Add trusted addresses + + + ) return (