diff --git a/centrifuge-app/src/components/AssetSummary.tsx b/centrifuge-app/src/components/AssetSummary.tsx index eb68636959..3b078fd42f 100644 --- a/centrifuge-app/src/components/AssetSummary.tsx +++ b/centrifuge-app/src/components/AssetSummary.tsx @@ -13,7 +13,7 @@ type Props = { loan?: Loan | TinlakeLoan } -export const AssetSummary: React.FC = ({ data, children, loan }) => { +export function AssetSummary({ data, children, loan }: Props) { const theme = useTheme() return ( diff --git a/centrifuge-app/src/components/BuyDialog.tsx b/centrifuge-app/src/components/BuyDialog.tsx deleted file mode 100644 index e6435632ba..0000000000 --- a/centrifuge-app/src/components/BuyDialog.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { useBalances, useCentrifugeTransaction } from '@centrifuge/centrifuge-react' -import { Button, Dialog, Shelf, Stack, Text } from '@centrifuge/fabric' -import BN from 'bn.js' -import * as React from 'react' -import { Dec } from '../utils/Decimal' -import { useAddress } from '../utils/useAddress' -import { useCentNFT } from '../utils/useNFTs' -import { ButtonGroup } from './ButtonGroup' - -type Props = { - open: boolean - onClose: () => void - collectionId: string - nftId: string -} -// TODO: replace with better fee estimate -const TRANSFER_FEE_ESTIMATE = 0.1 - -export const BuyDialog: React.FC = ({ open, onClose, collectionId, nftId }) => { - const address = useAddress('substrate') - const balances = useBalances(address) - const nft = useCentNFT(collectionId, nftId) - - const isConnected = !!address - - const { - execute: doTransaction, - reset: resetLastTransaction, - isLoading: transactionIsPending, - lastCreatedTransaction, - } = useCentrifugeTransaction('Buy NFT', (cent) => cent.nfts.buyNft) - - React.useEffect(() => { - if (lastCreatedTransaction?.status === 'pending') { - close() - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [lastCreatedTransaction?.status]) - - function submit(e: React.FormEvent) { - e.preventDefault() - if (!isConnected || !nft || nft.sellPrice === null) return - - doTransaction([collectionId, nftId, new BN(nft.sellPrice)]) - } - - function reset() { - resetLastTransaction() - } - - function close() { - reset() - onClose() - } - - const priceDec = Dec(nft?.sellPrice ?? 0).div('1e18') - const balanceDec = balances?.native.balance.toDecimal() ?? Dec(0) - - const balanceLow = balanceDec.lt(priceDec.add(Dec(TRANSFER_FEE_ESTIMATE))) - - const disabled = balanceLow || !nft - - function getMessage() { - if (balances == null) return - if (balanceDec.lt(priceDec)) return 'Insufficient funds to purchase this NFT' - if (balanceLow) return 'Insufficient funds to pay for transaction costs' - } - - const message = getMessage() - - return ( - -
- - - Buy NFT - - - - - - {nft?.sellPrice && `${formatPrice(priceDec.toNumber())} AIR`} - - {balances != null && {formatPrice(balanceDec.toNumber())} AIR balance} - - - - - {message && {message}} - - - - - - -
-
- ) -} - -function formatPrice(number: number) { - return number.toLocaleString('en', { maximumSignificantDigits: 2 }) -} diff --git a/centrifuge-app/src/components/Charts/AssetPerformanceChart.tsx b/centrifuge-app/src/components/Charts/AssetPerformanceChart.tsx index 9dc4a6bf2c..ed99949720 100644 --- a/centrifuge-app/src/components/Charts/AssetPerformanceChart.tsx +++ b/centrifuge-app/src/components/Charts/AssetPerformanceChart.tsx @@ -56,7 +56,7 @@ function AssetPerformanceChart({ pool, poolId, loanId }: Props) { } return getCSVDownloadUrl(assetSnapshots as any) - }, [assetSnapshots, pool.currency.symbol]) + }, [assetSnapshots]) const data: ChartData[] = React.useMemo(() => { if (!asset || !assetSnapshots) return [] @@ -79,7 +79,7 @@ function AssetPerformanceChart({ pool, poolId, loanId }: Props) { const today = new Date() today.setDate(today.getDate() + 1) const maturity = new Date(asset.pricing.maturityDate ?? '') - if (today.getTime() >= maturity.getTime() || assetSnapshots.length == 0) return historic + if (today.getTime() >= maturity.getTime() || assetSnapshots.length === 0) return historic const days = Math.floor((maturity.getTime() - today.getTime()) / (24 * 60 * 60 * 1000)) + 2 @@ -116,7 +116,7 @@ function AssetPerformanceChart({ pool, poolId, loanId }: Props) { } }), ] - }, [asset, assetSnapshots, activeFilter]) + }, [asset, assetSnapshots]) const priceRange = React.useMemo(() => { if (!data) return [0, 100] diff --git a/centrifuge-app/src/components/Charts/PoolPerformanceChart.tsx b/centrifuge-app/src/components/Charts/PoolPerformanceChart.tsx index 7b57475799..59b245991b 100644 --- a/centrifuge-app/src/components/Charts/PoolPerformanceChart.tsx +++ b/centrifuge-app/src/components/Charts/PoolPerformanceChart.tsx @@ -237,20 +237,12 @@ function CustomLegend({ borderLeftColor={theme.colors.accentPrimary} gap="4px" > - - - NAV - - + {formatBalance(data.nav, 'USD')}
{data.price && ( - - - Token price - - + {data.price ? formatBalance(data.price, 'USD', 6) : '-'} )} diff --git a/centrifuge-app/src/components/Charts/PriceYieldChart.tsx b/centrifuge-app/src/components/Charts/PriceYieldChart.tsx index ed1601dea4..9864d3955e 100644 --- a/centrifuge-app/src/components/Charts/PriceYieldChart.tsx +++ b/centrifuge-app/src/components/Charts/PriceYieldChart.tsx @@ -88,10 +88,7 @@ function PriceYieldChart({ ) : null } -const CustomLegend: React.VFC<{ - data: ChartData - poolId: string -}> = ({ data, poolId }) => { +function CustomLegend({ data, poolId }: { data: ChartData; poolId: string }) { const theme = useTheme() const pool = usePool(poolId) diff --git a/centrifuge-app/src/components/Charts/Tooltip.tsx b/centrifuge-app/src/components/Charts/Tooltip.tsx index 68743eaaac..37fb634801 100644 --- a/centrifuge-app/src/components/Charts/Tooltip.tsx +++ b/centrifuge-app/src/components/Charts/Tooltip.tsx @@ -6,7 +6,7 @@ import { formatBalance, formatPercentage } from '../../utils/formatting' type CustomizedTooltipProps = TooltipProps & { currency: string; precision?: number } -export const CustomizedTooltip: React.FC = ({ payload, currency, precision }) => { +export function CustomizedTooltip({ payload, currency, precision }: CustomizedTooltipProps) { if (payload && payload?.length > 0) { return ( diff --git a/centrifuge-app/src/components/CollectionCard.tsx b/centrifuge-app/src/components/CollectionCard.tsx index dc5e64ae9f..5928c1472d 100644 --- a/centrifuge-app/src/components/CollectionCard.tsx +++ b/centrifuge-app/src/components/CollectionCard.tsx @@ -14,7 +14,7 @@ type Props = { collection: Collection } -export const CollectionCard: React.FC = ({ collection }) => { +export function CollectionCard({ collection }: Props) { const [visible, setVisible] = React.useState(false) const ref = React.useRef(null) diff --git a/centrifuge-app/src/components/ContextActions.tsx b/centrifuge-app/src/components/ContextActions.tsx index cb6c60baab..938e87b17e 100644 --- a/centrifuge-app/src/components/ContextActions.tsx +++ b/centrifuge-app/src/components/ContextActions.tsx @@ -11,7 +11,7 @@ type Props = { } } -export const ContextActions: React.FC = ({ actions, parent }) => { +export function ContextActions({ actions, parent }: Props) { return ( {actions && ( diff --git a/centrifuge-app/src/components/DebugFlags/DebugFlags.tsx b/centrifuge-app/src/components/DebugFlags/DebugFlags.tsx index 32d10c8073..4e0efb2e0a 100644 --- a/centrifuge-app/src/components/DebugFlags/DebugFlags.tsx +++ b/centrifuge-app/src/components/DebugFlags/DebugFlags.tsx @@ -1,23 +1,17 @@ import { Box, Shelf, Stack, Text } from '@centrifuge/fabric' import * as React from 'react' import styled from 'styled-components' -import { Key, flagsConfig } from './config' -import { DebugFlagsContext, FlagsState, initialFlagsState, useDebugFlags } from './context' +import { Key, genericFlagsConfig } from './config' +import { DebugFlagsContext, Flags, initialFlagsState, useDebugFlags } from './context' -function DebugFlagsImpl({ - children, - onChange, -}: { - children?: React.ReactNode - onChange?: (state: FlagsState) => void -}) { +function DebugFlagsImpl({ children, onChange }: { children?: React.ReactNode; onChange?: (state: Flags) => void }) { const [state, setState] = React.useState(initialFlagsState) const [tracked, setTracked] = React.useState({}) const ctx = React.useMemo( () => ({ flags: Object.entries(state).reduce((obj, [key, value]) => { - const conf = flagsConfig[key as Key] + const conf = genericFlagsConfig[key as Key] obj[key] = 'options' in conf ? conf.options[value as string] : value return obj }, {} as any), @@ -56,11 +50,15 @@ function DebugFlagsImpl({ ) } -const Panel: React.FC<{ - state: FlagsState +function Panel({ + state, + usedKeys, + onChange, +}: { + state: Flags usedKeys: Set onChange: (key: Key, val: any) => void -}> = ({ state, usedKeys, onChange }) => { +}) { const [open, setOpen] = React.useState(false) const { showUnusedFlags } = useDebugFlags() @@ -81,7 +79,7 @@ const Panel: React.FC<{ {open && ( - {Object.entries(flagsConfig).map(([key, obj]) => { + {Object.entries(genericFlagsConfig).map(([key, obj]) => { const used = usedKeys.has(key) || obj.alwaysShow const value = state[key as Key] const visible = used || !!showUnusedFlags diff --git a/centrifuge-app/src/components/DebugFlags/config.ts b/centrifuge-app/src/components/DebugFlags/config.ts index b8571f016d..721323ed4c 100644 --- a/centrifuge-app/src/components/DebugFlags/config.ts +++ b/centrifuge-app/src/components/DebugFlags/config.ts @@ -35,7 +35,6 @@ export type Key = | 'showOrderExecution' | 'address' | 'evmAddress' - | 'batchMintNFTs' | 'persistDebugFlags' | 'showUnusedFlags' | 'allowInvestBelowMin' @@ -51,7 +50,7 @@ export type Key = | 'showTokenYields' | 'showOracleTx' -export const flagsConfig: Record = { +export const flagsConfig = { address: { default: '', type: 'text', @@ -65,10 +64,6 @@ export const flagsConfig: Record = { default: false, type: 'checkbox', }, - batchMintNFTs: { - default: false, - type: 'checkbox', - }, convertAddress: { Component: ConvertAddressDialogWithButton, alwaysShow: true, @@ -140,4 +135,6 @@ export const flagsConfig: Record = { default: false, type: 'checkbox', }, -} +} satisfies Record + +export const genericFlagsConfig = flagsConfig as Record diff --git a/centrifuge-app/src/components/DebugFlags/context.ts b/centrifuge-app/src/components/DebugFlags/context.ts index 8b37097a04..6366ffdd20 100644 --- a/centrifuge-app/src/components/DebugFlags/context.ts +++ b/centrifuge-app/src/components/DebugFlags/context.ts @@ -1,14 +1,13 @@ import * as React from 'react' -import { debug, flagsConfig, Key } from './config' +import { debug, flagsConfig, genericFlagsConfig, Key } from './config' export type Flags = { - [T in Key]: (typeof flagsConfig)[T] extends { options: { [key: string]: infer Y } } - ? Y + [T in Key]: (typeof flagsConfig)[T] extends { options: { [key: string]: string } } + ? string + : (typeof flagsConfig)[T]['default'] extends boolean + ? boolean : (typeof flagsConfig)[T]['default'] } -export type FlagsState = { - [T in Key]: (typeof flagsConfig)[T]['default'] -} interface Context { flags: Flags @@ -16,20 +15,20 @@ interface Context { unregister: (id: number) => void } -export const defaultFlags: Flags = Object.entries(flagsConfig).reduce((obj, [k, v]) => { - obj[k] = 'options' in v ? v.options[v.default as string] : v.default +export const defaultFlags: Flags = Object.entries(genericFlagsConfig).reduce((obj, [k, v]) => { + obj[k] = 'options' in v ? v.options[v.default] : v.default return obj }, {} as any) -let persistedState: FlagsState | null = null +let persistedState: Flags | null = null try { const stored = localStorage.getItem('debugFlags') ?? '' - persistedState = JSON.parse(stored[0] === '{' ? stored : '') as FlagsState + persistedState = JSON.parse(stored[0] === '{' ? stored : '') as Flags } catch (e) { // } const flagKeys = Object.keys(flagsConfig) -export const initialFlagsState: FlagsState = persistedState +export const initialFlagsState: Flags = persistedState ? Object.entries(persistedState) .filter(([k]) => flagKeys.includes(k)) .reduce((obj, [k, v]) => { diff --git a/centrifuge-app/src/components/DebugFlags/index.tsx b/centrifuge-app/src/components/DebugFlags/index.tsx index 6e97275ea5..b69937387a 100644 --- a/centrifuge-app/src/components/DebugFlags/index.tsx +++ b/centrifuge-app/src/components/DebugFlags/index.tsx @@ -1,18 +1,12 @@ import * as React from 'react' import { debug } from './config' -import { FlagsState } from './context' +import { Flags } from './context' export * from './context' const DebugFlagsImpl = React.lazy(() => import('./DebugFlags')) -export function DebugFlags({ - children, - onChange, -}: { - children?: React.ReactNode - onChange?: (state: FlagsState) => void -}) { +export function DebugFlags({ children, onChange }: { children?: React.ReactNode; onChange?: (state: Flags) => void }) { const fallback = <>{children} return debug ? ( diff --git a/centrifuge-app/src/components/Dialogs/CreateCollectionDialog.tsx b/centrifuge-app/src/components/Dialogs/CreateCollectionDialog.tsx index 1dacdc62a1..11b61495a1 100644 --- a/centrifuge-app/src/components/Dialogs/CreateCollectionDialog.tsx +++ b/centrifuge-app/src/components/Dialogs/CreateCollectionDialog.tsx @@ -33,7 +33,7 @@ const CREATE_FEE_ESTIMATE = 2 const MAX_FILE_SIZE_IN_BYTES = 1024 ** 2 // 1 MB limit by default const isImageFile = (file: File): boolean => !!file.type.match(/^image\//) -export const CreateCollectionDialog: React.FC<{ open: boolean; onClose: () => void }> = ({ open, onClose }) => { +export function CreateCollectionDialog({ open, onClose }: { open: boolean; onClose: () => void }) { const [name, setName] = React.useState('') const [description, setDescription] = React.useState('') const [logo, setLogo] = React.useState(null) diff --git a/centrifuge-app/src/components/Dialogs/ExecutiveSummaryDialog.tsx b/centrifuge-app/src/components/Dialogs/ExecutiveSummaryDialog.tsx index cabdb906f3..c49bdd9888 100644 --- a/centrifuge-app/src/components/Dialogs/ExecutiveSummaryDialog.tsx +++ b/centrifuge-app/src/components/Dialogs/ExecutiveSummaryDialog.tsx @@ -1,13 +1,17 @@ import { Box, Button, Dialog, IconInfo, Stack, Text } from '@centrifuge/fabric' -import * as React from 'react' import styled from 'styled-components' -export const ExecutiveSummaryDialog: React.FC<{ +export function ExecutiveSummaryDialog({ + issuerName, + href, + open, + onClose, +}: { issuerName: string href: string open: boolean onClose: () => void -}> = ({ issuerName, href, open, onClose }) => { +}) { return ( void -}> = ({ hash, open, onClose, error }) => { + error?: string +}) { return ( diff --git a/centrifuge-app/src/components/Dialogs/InvestmentDisclaimerDialog.tsx b/centrifuge-app/src/components/Dialogs/InvestmentDisclaimerDialog.tsx index 614aaa2849..b29d7b9350 100644 --- a/centrifuge-app/src/components/Dialogs/InvestmentDisclaimerDialog.tsx +++ b/centrifuge-app/src/components/Dialogs/InvestmentDisclaimerDialog.tsx @@ -1,10 +1,6 @@ import { Box, Button, Dialog, IconInfo, Stack, Text } from '@centrifuge/fabric' -import * as React from 'react' -export const InvestmentDisclaimerDialog: React.FC<{ - open: boolean - onClose: () => void -}> = ({ open, onClose }) => { +export function InvestmentDisclaimerDialog({ open, onClose }: { open: boolean; onClose: () => void }) { return ( void -}> = ({ preimageHash, open, onClose }) => { +}) { return ( diff --git a/centrifuge-app/src/components/Dialogs/RemoveListingDialog.tsx b/centrifuge-app/src/components/Dialogs/RemoveListingDialog.tsx deleted file mode 100644 index b1734d0207..0000000000 --- a/centrifuge-app/src/components/Dialogs/RemoveListingDialog.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { useBalances, useCentrifuge, useCentrifugeTransaction, useWallet } from '@centrifuge/centrifuge-react' -import { Button, Dialog, Shelf, Stack, Text } from '@centrifuge/fabric' -import * as React from 'react' -import { Dec } from '../../utils/Decimal' -import { useAddress } from '../../utils/useAddress' -import { useCentNFT } from '../../utils/useNFTs' -import { ButtonGroup } from '../ButtonGroup' - -type Props = { - open: boolean - onClose: () => void - collectionId: string - nftId: string -} -// TODO: replace with better fee estimate -const TRANSFER_FEE_ESTIMATE = 0.1 - -export const RemoveListingDialog: React.FC = ({ open, onClose, collectionId, nftId }) => { - const { substrate } = useWallet() - const address = useAddress('substrate') - const balances = useBalances(address) - const centrifuge = useCentrifuge() - const nft = useCentNFT(collectionId, nftId) - - const isConnected = !!substrate.selectedAccount?.address - - const { - execute: doTransaction, - reset: resetLastTransaction, - isLoading: transactionIsPending, - lastCreatedTransaction, - } = useCentrifugeTransaction('Remove NFT listing', (cent) => cent.nfts.removeNftListing) - - React.useEffect(() => { - if (lastCreatedTransaction?.status === 'pending') { - close() - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [lastCreatedTransaction?.status]) - - function submit(e: React.FormEvent) { - e.preventDefault() - if (!isConnected) return - - doTransaction([collectionId, nftId]) - } - - function reset() { - resetLastTransaction() - } - - function close() { - reset() - onClose() - } - - const balanceDec = balances?.native.balance.toDecimal() ?? Dec(0) - const balanceLow = balanceDec.lt(TRANSFER_FEE_ESTIMATE) - - const disabled = balanceLow - - return ( - -
- - - Are you sure about removing this listing? - - - - - {nft?.sellPrice && centrifuge.utils.formatCurrencyAmount(nft.sellPrice, 'AIR')} - - - - - {balanceLow && ( - - Your balance is too low ({(balanceDec || 0).toFixed(2)} AIR) - - )} - - - - - - -
-
- ) -} diff --git a/centrifuge-app/src/components/Dialogs/SellDialog.tsx b/centrifuge-app/src/components/Dialogs/SellDialog.tsx deleted file mode 100644 index d26c882728..0000000000 --- a/centrifuge-app/src/components/Dialogs/SellDialog.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import { useBalances, useCentrifugeTransaction } from '@centrifuge/centrifuge-react' -import { Button, CurrencyInput, Dialog, Shelf, Stack, Text } from '@centrifuge/fabric' -import BN from 'bn.js' -import * as React from 'react' -import { Dec } from '../../utils/Decimal' -import { useAddress } from '../../utils/useAddress' -import { ButtonGroup } from '../ButtonGroup' - -const e18 = new BN(10).pow(new BN(18)) - -type Props = { - open: boolean - onClose: () => void - collectionId: string - nftId: string -} -// TODO: replace with better fee estimate -const TRANSFER_FEE_ESTIMATE = 0.1 - -export const SellDialog: React.FC = ({ open, onClose, collectionId, nftId }) => { - const [price, setPrice] = React.useState('') - const [touched, setTouched] = React.useState(false) - const address = useAddress('substrate') - const balances = useBalances(address) - - const { - execute: doTransaction, - reset: resetLastTransaction, - isLoading: transactionIsPending, - lastCreatedTransaction, - } = useCentrifugeTransaction('List NFT for sale', (cent) => cent.nfts.sellNft) - - React.useEffect(() => { - if (lastCreatedTransaction?.status === 'pending') { - close() - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [lastCreatedTransaction?.status]) - - function submit(e: React.FormEvent) { - e.preventDefault() - if (!!error) return - if (!price) return - const amountBN = new BN(price).mul(e18) - doTransaction([collectionId, nftId, amountBN]) - } - - function reset() { - setPrice('') - setTouched(false) - resetLastTransaction() - } - - function close() { - reset() - onClose() - } - - function getError() { - if (!price && price !== 0) return 'Invalid price' - if (price < 0) return "Price can't be negative" - if (price > Number.MAX_SAFE_INTEGER) return 'Price too high' - return null - } - - const error = getError() - - const balanceDec = balances?.native.balance.toDecimal() ?? Dec(0) - const balanceLow = balanceDec.lt(TRANSFER_FEE_ESTIMATE) - - const disabled = !!error || balanceLow - - return ( - -
- - - Sell NFT - - Enter item price - setPrice(value)} - errorMessage={(touched && error) || undefined} - onBlur={() => setTouched(true)} - currency="AIR" - /> - - {balanceLow && ( - - Your balance is too low ({(balanceDec || 0).toFixed(2)} AIR) - - )} - - - - - - -
-
- ) -} diff --git a/centrifuge-app/src/components/Dialogs/TransferDialog.tsx b/centrifuge-app/src/components/Dialogs/TransferDialog.tsx index 212b62f33d..e4257d1627 100644 --- a/centrifuge-app/src/components/Dialogs/TransferDialog.tsx +++ b/centrifuge-app/src/components/Dialogs/TransferDialog.tsx @@ -16,7 +16,7 @@ type Props = { // TODO: replace with better fee estimate const TRANSFER_FEE_ESTIMATE = 0.1 -export const TransferDialog: React.FC = ({ open, onClose, collectionId, nftId }) => { +export function TransferDialog({ open, onClose, collectionId, nftId }: Props) { const [address, setAddress] = React.useState('') const [touched, setTouched] = React.useState(false) const connectedAddress = useAddress('substrate') diff --git a/centrifuge-app/src/components/EpochList.tsx b/centrifuge-app/src/components/EpochList.tsx index 77b95d0868..79a0ff03ac 100644 --- a/centrifuge-app/src/components/EpochList.tsx +++ b/centrifuge-app/src/components/EpochList.tsx @@ -43,7 +43,7 @@ export const columns: Column[] = [ // }, ] -export const EpochList: React.FC = ({ pool }) => { +export function EpochList({ pool }: Props) { // const theme = useTheme() const { // sumOfExecutableInvestments, @@ -155,7 +155,7 @@ export const EpochList: React.FC = ({ pool }) => { ) } -const LockedRow: React.VFC<{ row: LiquidityTableRow }> = ({ row }) => { +function LockedRow({ row }: { row: LiquidityTableRow }) { const { pid: poolId } = useParams<{ pid: string }>() if (!poolId) throw new Error('Pool not found') @@ -166,7 +166,7 @@ const LockedRow: React.VFC<{ row: LiquidityTableRow }> = ({ row }) => { ) } -// const ExecutingRow: React.VFC<{ row: LiquidityTableRow }> = ({ row }) => { +// function ExecutingRow({ row }: { row: LiquidityTableRow }) { // const { pid: poolId } = useParams<{ pid: string }>() // const pool = usePool(poolId) // return ( @@ -174,7 +174,7 @@ const LockedRow: React.VFC<{ row: LiquidityTableRow }> = ({ row }) => { // ) // } -// const ExecutingPercentageRow: React.VFC<{ row: LiquidityTableRow }> = ({ row }) => { +// function ExecutingPercentageRow({ row }: { row: LiquidityTableRow }) { // return ( // <> // {React.isValidElement(row.executingPercentage) diff --git a/centrifuge-app/src/components/FieldWithErrorMessage.tsx b/centrifuge-app/src/components/FieldWithErrorMessage.tsx index 3b65792695..eef59b73ef 100644 --- a/centrifuge-app/src/components/FieldWithErrorMessage.tsx +++ b/centrifuge-app/src/components/FieldWithErrorMessage.tsx @@ -5,7 +5,7 @@ type Props = FieldAttributes & { label?: string | React.ReactElement } -export const FieldWithErrorMessage: React.FC = (props) => { +export function FieldWithErrorMessage(props: Props) { const [, meta] = useField(props) return } diff --git a/centrifuge-app/src/components/Identity.tsx b/centrifuge-app/src/components/Identity.tsx index 9d1d90e046..89c38aa314 100644 --- a/centrifuge-app/src/components/Identity.tsx +++ b/centrifuge-app/src/components/Identity.tsx @@ -23,13 +23,7 @@ const IdenticonWrapper = styled(Flex)({ }) // TODO: Fix for when connected with a proxy -export const Identity: React.FC = ({ - showIcon, - address, - clickToCopy, - labelForConnectedAddress = true, - ...textProps -}) => { +export function Identity({ showIcon, address, clickToCopy, labelForConnectedAddress = true, ...textProps }: Props) { const identity = useIdentity(address) const myAddress = useAddress('substrate') const utils = useCentrifugeUtils() diff --git a/centrifuge-app/src/components/InvestRedeem/InvestRedeemDrawer.tsx b/centrifuge-app/src/components/InvestRedeem/InvestRedeemDrawer.tsx index 8305aa8167..1b222a8e54 100644 --- a/centrifuge-app/src/components/InvestRedeem/InvestRedeemDrawer.tsx +++ b/centrifuge-app/src/components/InvestRedeem/InvestRedeemDrawer.tsx @@ -88,7 +88,7 @@ const TokenPriceChart = React.memo(function TokenPriceChart({ }) } return tokenData - }, [dailyPoolStates, filter, trancheId]) + }, [dailyPoolStates, pool?.tranches, trancheId]) return ( = ({ label, value, renderAs }) => { +export function LabelValueStack({ label, value, renderAs }: Props) { return ( diff --git a/centrifuge-app/src/components/LiquidityTransactionsSection.tsx b/centrifuge-app/src/components/LiquidityTransactionsSection.tsx index 51e439371b..640cf56c4e 100644 --- a/centrifuge-app/src/components/LiquidityTransactionsSection.tsx +++ b/centrifuge-app/src/components/LiquidityTransactionsSection.tsx @@ -76,7 +76,7 @@ export default function LiquidityTransactionsSection({ })) return getCSVDownloadUrl(formatted) - }, [dailyPoolStates, dataKeys, dataNames, pool.currency.symbol]) + }, [dailyPoolStates, dataKeys, dataNames, pool.currency.decimals, pool.currency.symbol]) const chartData = React.useMemo(() => { return (dailyPoolStates @@ -105,7 +105,7 @@ export default function LiquidityTransactionsSection({ }) .slice(-rangeNumber) .filter(Boolean) || []) as StackedBarChartProps['data'] - }, [dailyPoolStates, dataKeys, rangeNumber]) + }, [dailyPoolStates, dataKeys, pool.currency.decimals, rangeNumber]) const legend: LegendProps['data'] = React.useMemo(() => { const topTotal = chartData.map(({ top }) => top).reduce((a, b) => a + b, 0) diff --git a/centrifuge-app/src/components/LogoAltair.tsx b/centrifuge-app/src/components/LogoAltair.tsx index ee4f822dba..ebe74067fe 100644 --- a/centrifuge-app/src/components/LogoAltair.tsx +++ b/centrifuge-app/src/components/LogoAltair.tsx @@ -7,7 +7,7 @@ const SVG = styled.svg` height: auto; ` -export const LogoAltair: React.FC, 'ref'>> = (props) => { +export function LogoAltair(props: Omit, 'ref'>) { return ( , 'ref'>> = ) } -export const LogoAltairText: React.FC, 'ref'>> = (props) => { +export function LogoAltairText() { return ( diff --git a/centrifuge-app/src/components/LogoCentrifuge.tsx b/centrifuge-app/src/components/LogoCentrifuge.tsx index 658b651520..5651b42ab4 100644 --- a/centrifuge-app/src/components/LogoCentrifuge.tsx +++ b/centrifuge-app/src/components/LogoCentrifuge.tsx @@ -7,7 +7,7 @@ const SVG = styled.svg` height: auto; ` -export const LogoCentrifugeText: React.FC, 'ref'>> = (props) => { +export function LogoCentrifugeText(props: Omit, 'ref'>) { return ( , 'r ) } -export const LogoCentrifuge: React.FC, 'ref'>> = (props) => { +export function LogoCentrifuge(props: Omit, 'ref'>) { return ( = ({ nft }) => { +export function NFTCard({ nft }: Props) { const [visible, setVisible] = React.useState(false) const ref = React.useRef(null) @@ -73,11 +73,6 @@ export const NFTCard: React.FC = ({ nft }) => {
)} - {nft.sellPrice !== null && ( - - {centrifuge.utils.formatCurrencyAmount(nft.sellPrice, 'AIR')} - - )} diff --git a/centrifuge-app/src/components/PageHeader.tsx b/centrifuge-app/src/components/PageHeader.tsx index 24b9ded063..446d5ebc59 100644 --- a/centrifuge-app/src/components/PageHeader.tsx +++ b/centrifuge-app/src/components/PageHeader.tsx @@ -23,7 +23,7 @@ type Props = { children?: React.ReactNode } -export const PageHeader: React.FC = ({ +export function PageHeader({ title, titleAddition, subtitle, @@ -34,7 +34,7 @@ export const PageHeader: React.FC = ({ border = true, parent, children, -}) => { +}: Props) { const theme = useTheme() return ( diff --git a/centrifuge-app/src/components/PageSection.tsx b/centrifuge-app/src/components/PageSection.tsx index ebfd086160..8681196346 100644 --- a/centrifuge-app/src/components/PageSection.tsx +++ b/centrifuge-app/src/components/PageSection.tsx @@ -32,7 +32,7 @@ const CollapseButton = styled(Shelf)` } ` -export const PageSection: React.FC = ({ +export function PageSection({ title, titleAddition, subtitle, @@ -40,7 +40,7 @@ export const PageSection: React.FC = ({ collapsible, defaultOpen = false, children, -}) => { +}: Props) { const [open, setOpen] = React.useState(defaultOpen) return ( = ({ data, children }) => { +export function PageSummary({ data, children }: Props) { const theme = useTheme() return ( ( type PillProps = PropsOf & { variant?: 'small' | 'regular' } -export const PillButton: React.FC = ({ children, variant = 'regular', ...rest }) => { +export function PillButton({ children, variant = 'regular', ...rest }: PillProps) { return ( @@ -52,8 +52,6 @@ export const PillButton: React.FC = ({ children, variant = 'regular', ) } -export const AnchorPillButton: React.FC & { variant?: 'small' | 'regular' }> = ( - props -) => { +export function AnchorPillButton(props: React.ComponentPropsWithoutRef<'a'> & { variant?: 'small' | 'regular' }) { return } diff --git a/centrifuge-app/src/components/PoolFilter/FilterMenu.tsx b/centrifuge-app/src/components/PoolFilter/FilterMenu.tsx index bb64781693..7c5e6c20f3 100644 --- a/centrifuge-app/src/components/PoolFilter/FilterMenu.tsx +++ b/centrifuge-app/src/components/PoolFilter/FilterMenu.tsx @@ -19,16 +19,11 @@ export function FilterMenu({ label, options, searchKey, tooltip }: FilterMenuPro const form = React.useRef(null) - const restSearchParams = React.useMemo(() => { - const searchParams = new URLSearchParams(search) - searchParams.delete(searchKey) - return searchParams - }, [search]) + const restSearchParams = new URLSearchParams(search) + restSearchParams.delete(searchKey) - const selectedOptions = React.useMemo(() => { - const searchParams = new URLSearchParams(search) - return searchParams.getAll(searchKey) - }, [search]) + const searchParams = new URLSearchParams(search) + const selectedOptions = searchParams.getAll(searchKey) function handleChange() { const formData = new FormData(form.current ?? undefined) @@ -61,7 +56,7 @@ export function FilterMenu({ label, options, searchKey, tooltip }: FilterMenuPro { + renderTrigger={(props, ref) => { return ( diff --git a/centrifuge-app/src/components/PoolFilter/SortButton.tsx b/centrifuge-app/src/components/PoolFilter/SortButton.tsx index 1dd6b4590c..ad94c69b85 100644 --- a/centrifuge-app/src/components/PoolFilter/SortButton.tsx +++ b/centrifuge-app/src/components/PoolFilter/SortButton.tsx @@ -29,7 +29,7 @@ export function SortButton({ label, searchKey, tooltip, justifySelf = 'end' }: S isActive: searchParams.get(SEARCH_KEYS.SORT_BY) === searchKey, direction: searchParams.get(SEARCH_KEYS.SORT), } - }, [search]) + }, [search, searchKey]) function handleClick() { const restSearchParams = new URLSearchParams(search) @@ -59,7 +59,6 @@ export function SortButton({ label, searchKey, tooltip, justifySelf = 'end' }: S ? `Sort ${label} descending` : `Sort ${label} ascending` } - aria-live style={{ justifySelf }} > @@ -83,7 +82,6 @@ export function SortButton({ label, searchKey, tooltip, justifySelf = 'end' }: S ? `Sort ${label} descending` : `Sort ${label} ascending` } - aria-live style={{ justifySelf }} > {label} diff --git a/centrifuge-app/src/components/PoolOverview/PoolStructure.tsx b/centrifuge-app/src/components/PoolOverview/PoolStructure.tsx index 4f31bf087a..cb79062122 100644 --- a/centrifuge-app/src/components/PoolOverview/PoolStructure.tsx +++ b/centrifuge-app/src/components/PoolOverview/PoolStructure.tsx @@ -1,10 +1,7 @@ import { Rate } from '@centrifuge/centrifuge-js' -import { getChainInfo, useWallet } from '@centrifuge/centrifuge-react' import { Box, Card, Grid, Stack, Text, Tooltip } from '@centrifuge/fabric' import capitalize from 'lodash/capitalize' import { formatPercentage } from '../../utils/formatting' -import { useActiveDomains } from '../../utils/useLiquidityPools' -import { useInvestorTransactions } from '../../utils/usePools' type Props = { numOfTranches: number @@ -17,23 +14,7 @@ type Props = { }[] } -export const PoolStructure = ({ numOfTranches, poolId, poolStatus, poolFees }: Props) => { - const investorTransactions = useInvestorTransactions(poolId) - const { data: domains } = useActiveDomains(poolId) - const { - evm: { chains }, - } = useWallet() - - const firstInvestment = investorTransactions?.find( - (investorTransaction) => investorTransaction.type === 'INVEST_EXECUTION' - )?.timestamp - const deployedLpChains = - domains - ?.filter((domain) => domain.isActive === true) - .map((domain) => { - return getChainInfo(chains, domain.chainId).name - }) ?? [] - +export const PoolStructure = ({ numOfTranches, poolStatus, poolFees }: Props) => { const metrics = [ { metric: 'Pool type', @@ -47,10 +28,6 @@ export const PoolStructure = ({ numOfTranches, poolId, poolStatus, poolFees }: P metric: 'Tranche structure', value: numOfTranches === 1 ? 'Unitranche' : `${numOfTranches} tranches`, }, - // { - // metric: 'First investment', - // value: firstInvestment ? formatDate(firstInvestment) : '-', - // }, ...poolFees.map((fee) => { return { metric: fee.name, diff --git a/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx b/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx index 1ff08cdd79..4568215bf0 100644 --- a/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx +++ b/centrifuge-app/src/components/PoolOverview/TransactionHistory.tsx @@ -46,14 +46,14 @@ export const columns = [ align: 'left', header: 'Asset', cell: ({ activeAssetId, assetId, assetName, fromAssetId, fromAssetName, toAssetId, toAssetName }: Row) => { - return fromAssetId && toAssetId && activeAssetId == fromAssetId.split('-')[1] ? ( + return fromAssetId && toAssetId && activeAssetId === fromAssetId.split('-')[1] ? ( {fromAssetName} →{' '} {toAssetName} - ) : fromAssetId && toAssetId && activeAssetId == toAssetId.split('-')[1] ? ( + ) : fromAssetId && toAssetId && activeAssetId === toAssetId.split('-')[1] ? ( {fromAssetName} @@ -70,7 +70,7 @@ export const columns = [ {toAssetName} - ) : activeAssetId != assetId?.split('-')[1] ? ( + ) : activeAssetId !== assetId?.split('-')[1] ? ( {assetName || `Asset ${assetId?.split('-')[1]}`} diff --git a/centrifuge-app/src/components/Portfolio/TransferTokensDrawer.tsx b/centrifuge-app/src/components/Portfolio/TransferTokensDrawer.tsx index 90c9405aaf..b07a2155d2 100644 --- a/centrifuge-app/src/components/Portfolio/TransferTokensDrawer.tsx +++ b/centrifuge-app/src/components/Portfolio/TransferTokensDrawer.tsx @@ -65,7 +65,7 @@ export const TransferTokensDrawer = ({ address, onClose, isOpen }: TransferToken } } return centBalances?.currencies.find((token) => token.currency.symbol === transferCurrencySymbol) - }, [centBalances, transferCurrencySymbol]) + }, [centBalances, isNativeTransfer, transferCurrencySymbol]) const tokenPrice = isNativeTransfer ? CFGPrice : 1 @@ -299,10 +299,7 @@ const SendToken = ({ address, currency, isNativeTransfer }: SendReceiveProps) => const ReceiveToken = ({ address }: SendReceiveProps) => { const utils = useCentrifugeUtils() const [copied, setCopied] = React.useState(false) - const centAddress = useMemo( - () => (address && address.startsWith('0x') ? utils.formatAddress(address) : address), - [address] - ) + const centAddress = address && address.startsWith('0x') ? utils.formatAddress(address) : address return ( @@ -365,7 +362,7 @@ const CFGPriceChart = React.memo(function CFGPriceChart() { }) } return tokenData - }, [tokenDayData, filter]) + }, [tokenDayData?.data?.tokenDayDatas, currentCFGPrice]) return }) diff --git a/centrifuge-app/src/components/Portfolio/usePortfolio.ts b/centrifuge-app/src/components/Portfolio/usePortfolio.ts index a09214e482..585a961afd 100644 --- a/centrifuge-app/src/components/Portfolio/usePortfolio.ts +++ b/centrifuge-app/src/components/Portfolio/usePortfolio.ts @@ -95,7 +95,7 @@ export function useDailyPortfolioValue(address: string, rangeValue?: number) { ) }) } - }, [dailyTrancheStatesByTrancheId, rangeValue, transactionsByTrancheId]) + }, [dailyTrancheStatesByTrancheId, daysSinceFirstTx, rangeDays, rangeValue, transactionsByTrancheId]) } const getPriceAtDate = ( diff --git a/centrifuge-app/src/components/Report/BalanceSheet.tsx b/centrifuge-app/src/components/Report/BalanceSheet.tsx index 78ef9f37c9..0a17484d59 100644 --- a/centrifuge-app/src/components/Report/BalanceSheet.tsx +++ b/centrifuge-app/src/components/Report/BalanceSheet.tsx @@ -49,7 +49,7 @@ export function BalanceSheet({ pool }: { pool: Pool }) { to.setHours(0, 0, 0, 0) return [new Date(startDate), to] } - }, [groupBy, startDate, endDate]) + }, [groupBy, startDate, endDate, pool.createdAt]) const poolStates = usePoolStatesByGroup( pool.id, @@ -96,7 +96,7 @@ export function BalanceSheet({ pool }: { pool: Pool }) { cell: () => , width: '1fr', }) - }, [poolStates, groupBy, pool]) + }, [poolStates]) const assetValuationRecords: Row[] = React.useMemo(() => { return [ @@ -137,7 +137,7 @@ export function BalanceSheet({ pool }: { pool: Pool }) { formatter: (v: any) => (v ? formatBalance(v, pool.currency.displayName, 2) : ''), }, ] - }, [poolStates]) + }, [pool.currency.displayName, poolStates]) const trancheRecords: Row[] = React.useMemo(() => { return [ diff --git a/centrifuge-app/src/components/Report/CashflowStatement.tsx b/centrifuge-app/src/components/Report/CashflowStatement.tsx index 7fde486ca1..3fba374d8b 100644 --- a/centrifuge-app/src/components/Report/CashflowStatement.tsx +++ b/centrifuge-app/src/components/Report/CashflowStatement.tsx @@ -55,7 +55,7 @@ export function CashflowStatement({ pool }: { pool: Pool }) { to.setHours(0, 0, 0, 0) return [new Date(startDate), to] } - }, [groupBy, startDate, endDate]) + }, [groupBy, startDate, endDate, pool.createdAt]) const poolStates = useAggregatedPoolStatesByGroup( pool.id, @@ -140,7 +140,7 @@ export function CashflowStatement({ pool }: { pool: Pool }) { cell: () => , width: '1fr', }) - }, [poolStates, groupBy, pool, poolFeeStates]) + }, [poolStates, groupBy]) const grossCashflowRecords: Row[] = React.useMemo(() => { return [ @@ -198,7 +198,7 @@ export function CashflowStatement({ pool }: { pool: Pool }) { formatter: (v: any) => (v ? formatBalance(v, pool.currency.displayName, 2) : ''), }, ] - }, [poolStates]) + }, [pool.currency.displayName, poolMetadata?.pool?.asset.class, poolStates]) const netCashflowRecords: Row[] = React.useMemo(() => { return [ @@ -306,7 +306,7 @@ export function CashflowStatement({ pool }: { pool: Pool }) { formatter: (v: any) => (v ? formatBalance(v, pool.currency.displayName, 2) : ''), }, ] - }, [poolStatesNotAggregated, pool]) + }, [poolStates, poolStatesNotAggregated, pool.currency.displayName]) const headers = columns.slice(0, -1).map(({ header }) => header) diff --git a/centrifuge-app/src/components/Report/InvestorList.tsx b/centrifuge-app/src/components/Report/InvestorList.tsx index 4acf59534a..51ac751192 100644 --- a/centrifuge-app/src/components/Report/InvestorList.tsx +++ b/centrifuge-app/src/components/Report/InvestorList.tsx @@ -136,6 +136,7 @@ export function InvestorList({ pool }: { pool: Pool }) { const addressValue = row.value[1] as string return isAddress(address) && isSameAddress(address, addressValue) }) + // eslint-disable-next-line react-hooks/exhaustive-deps }, [investors, network, pool, address]) const dataUrl = React.useMemo(() => { diff --git a/centrifuge-app/src/components/Report/OracleTransactions.tsx b/centrifuge-app/src/components/Report/OracleTransactions.tsx index 593a3d6ab3..37d4d5652e 100644 --- a/centrifuge-app/src/components/Report/OracleTransactions.tsx +++ b/centrifuge-app/src/components/Report/OracleTransactions.tsx @@ -14,7 +14,7 @@ import type { TableDataRow } from './index' const noop = (v: any) => v export function OracleTransactions({ pool }: { pool: Pool }) { - const { startDate, endDate, setCsvData, txType } = React.useContext(ReportContext) + const { startDate, endDate, setCsvData } = React.useContext(ReportContext) const transactions = useOracleTransactions(new Date(startDate), new Date(endDate)) const columnConfig = [ @@ -38,17 +38,12 @@ export function OracleTransactions({ pool }: { pool: Pool }) { }, ] - const data: TableDataRow[] = React.useMemo(() => { - if (!transactions) { - return [] - } - - return transactions.map((tx) => ({ + const data: TableDataRow[] = + transactions?.map((tx) => ({ name: '', value: [tx.timestamp.toISOString(), tx.key?.substring(2) || '-', tx.value?.toFloat() ?? '-'], heading: false, - })) - }, [transactions, txType, pool.currency.symbol]) + })) || [] const columns = columnConfig .map((col, index) => ({ diff --git a/centrifuge-app/src/components/Report/ProfitAndLoss.tsx b/centrifuge-app/src/components/Report/ProfitAndLoss.tsx index a1159b2185..a0d3dbdceb 100644 --- a/centrifuge-app/src/components/Report/ProfitAndLoss.tsx +++ b/centrifuge-app/src/components/Report/ProfitAndLoss.tsx @@ -54,7 +54,7 @@ export function ProfitAndLoss({ pool }: { pool: Pool }) { to.setHours(0, 0, 0, 0) return [new Date(startDate), to] } - }, [groupBy, startDate, endDate]) + }, [groupBy, startDate, endDate, pool.createdAt]) const poolStates = useAggregatedPoolStatesByGroup( pool.id, @@ -132,7 +132,7 @@ export function ProfitAndLoss({ pool }: { pool: Pool }) { cell: () => , width: '1fr', }) - }, [poolStates, groupBy, pool]) + }, [poolStates, groupBy]) const profitAndLossPublicRecords: Row[] = React.useMemo(() => { return [ @@ -175,7 +175,7 @@ export function ProfitAndLoss({ pool }: { pool: Pool }) { formatter: (v: any) => (v ? formatBalance(v, pool.currency.displayName, 2) : ''), }, ] - }, [poolStates]) + }, [pool.currency.displayName, poolStates]) const profitAndLossPrivateRecords: Row[] = React.useMemo(() => { return [ @@ -224,7 +224,7 @@ export function ProfitAndLoss({ pool }: { pool: Pool }) { formatter: (v: any) => (v ? formatBalance(v, pool.currency.displayName, 2) : ''), }, ] - }, [poolStates]) + }, [pool.currency.displayName, poolStates]) const profitAndLossRecords = poolMetadata?.pool?.asset.class === 'Private credit' ? profitAndLossPrivateRecords : profitAndLossPublicRecords @@ -311,7 +311,7 @@ export function ProfitAndLoss({ pool }: { pool: Pool }) { formatter: (v: any) => `${formatBalance(v, pool.currency.displayName, 2)}`, }, ] - }, [poolStates, pool]) + }, [poolStates, poolMetadata?.pool?.asset.class, pool.currency.displayName]) const headers = columns.slice(0, -1).map(({ header }) => header) diff --git a/centrifuge-app/src/components/Report/ReportFilter.tsx b/centrifuge-app/src/components/Report/ReportFilter.tsx index 704e9ccc13..d47c0942db 100644 --- a/centrifuge-app/src/components/Report/ReportFilter.tsx +++ b/centrifuge-app/src/components/Report/ReportFilter.tsx @@ -56,7 +56,7 @@ export function ReportFilter({ pool }: ReportFilterProps) { { label: 'Investor transactions', value: 'investor-tx' }, { label: 'Asset transactions', value: 'asset-tx' }, { label: 'Fee transactions', value: 'fee-tx' }, - ...(showOracleTx == true ? [{ label: 'Oracle transactions', value: 'oracle-tx' as Report }] : []), + ...(showOracleTx === true ? [{ label: 'Oracle transactions', value: 'oracle-tx' as Report }] : []), // { label: 'Pool balance', value: 'pool-balance' }, { label: 'Token price', value: 'token-price' }, { label: 'Asset list', value: 'asset-list' }, diff --git a/centrifuge-app/src/components/Report/TokenPrice.tsx b/centrifuge-app/src/components/Report/TokenPrice.tsx index 56ef801102..ac6a7ab496 100644 --- a/centrifuge-app/src/components/Report/TokenPrice.tsx +++ b/centrifuge-app/src/components/Report/TokenPrice.tsx @@ -70,7 +70,7 @@ export function TokenPrice({ pool }: { pool: Pool }) { cell: () => , width: '1fr', }) - }, [poolStates, groupBy, pool]) + }, [poolStates, groupBy]) const priceRecords: Row[] = React.useMemo(() => { return [ diff --git a/centrifuge-app/src/components/Root.tsx b/centrifuge-app/src/components/Root.tsx index b01e67cee0..2ce8df38d4 100644 --- a/centrifuge-app/src/components/Root.tsx +++ b/centrifuge-app/src/components/Root.tsx @@ -82,9 +82,9 @@ export function Root() { evmChains={evmChains} subscanUrl={import.meta.env.REACT_APP_SUBSCAN_URL} walletConnectId={import.meta.env.REACT_APP_WALLETCONNECT_ID} - showAdvancedAccounts={debugState.showAdvancedAccounts as any} - showTestNets={debugState.showTestNets as any} - showFinoa={debugState.showFinoa as any} + showAdvancedAccounts={debugState.showAdvancedAccounts} + showTestNets={debugState.showTestNets} + showFinoa={debugState.showFinoa} > @@ -186,7 +186,7 @@ export function prefetchRoute(to: string | NavLinkProps['to']) { const route = pathname ? findRoute(pathname) : null const Comp = route?.route.element try { - if (Comp && '_init' in Comp && '_payload' in Comp) Comp._init(Comp._payload) + if (Comp && '_init' in Comp && '_payload' in Comp) (Comp as any)._init(Comp._payload) } catch (error) { console.error('Error prefetching route:', error) } diff --git a/centrifuge-app/src/components/RouterLinkButton.tsx b/centrifuge-app/src/components/RouterLinkButton.tsx index 13b2de342c..8204253134 100644 --- a/centrifuge-app/src/components/RouterLinkButton.tsx +++ b/centrifuge-app/src/components/RouterLinkButton.tsx @@ -1,8 +1,6 @@ import { VisualButton, VisualButtonProps } from '@centrifuge/fabric' -import * as React from 'react' import { NavLink, NavLinkProps } from 'react-router-dom' import styled from 'styled-components' -import { useLinkIsActive } from '../utils/useLinkIsActive' import { prefetchRoute } from './Root' export type RouterLinkButtonProps = VisualButtonProps & NavLinkProps & { showActive?: boolean } @@ -16,7 +14,7 @@ const StyledLink = styled(NavLink)<{ $disabled?: boolean }>( (props) => props.$disabled && { pointerEvents: 'none' } ) -export const RouterLinkButton: React.FC = ({ +export function RouterLinkButton({ variant, small, icon, @@ -25,11 +23,8 @@ export const RouterLinkButton: React.FC = ({ loading, loadingMessage, children, - showActive = false, ...routeProps -}) => { - const isActive = useLinkIsActive(routeProps) - +}: RouterLinkButtonProps) { return ( prefetchRoute(routeProps.to)}> = ({ disabled={disabled} loading={loading} loadingMessage={loadingMessage} - active={showActive && isActive} > {children} diff --git a/centrifuge-app/src/components/TextLink.tsx b/centrifuge-app/src/components/TextLink.tsx index dc064c0f8b..820df816f9 100644 --- a/centrifuge-app/src/components/TextLink.tsx +++ b/centrifuge-app/src/components/TextLink.tsx @@ -39,6 +39,6 @@ ButtonTextLink.defaultProps = { type: 'button', } -export const AnchorTextLink: React.FC> = (props) => { +export function AnchorTextLink(props: React.ComponentPropsWithoutRef<'a'>) { return } diff --git a/centrifuge-app/src/components/TokenList.tsx b/centrifuge-app/src/components/TokenList.tsx index b06731587b..4490676b79 100644 --- a/centrifuge-app/src/components/TokenList.tsx +++ b/centrifuge-app/src/components/TokenList.tsx @@ -1,7 +1,6 @@ import { useBasePath } from '@centrifuge/centrifuge-app/src/utils/useBasePath' import { CurrencyMetadata, PoolMetadata } from '@centrifuge/centrifuge-js' import { IconChevronRight, Shelf, Text, TextWithPlaceholder, Thumbnail } from '@centrifuge/fabric' -import * as React from 'react' import { formatBalance, formatBalanceAbbreviated, formatPercentage } from '../utils/formatting' import { usePoolMetadata } from '../utils/usePools' import { Column, DataTable, SortableTableHeader } from './DataTable' @@ -79,7 +78,7 @@ const columns: Column[] = [ }, ] -export const TokenList: React.FC = ({ tokens }) => { +export function TokenList({ tokens }: Props) { const basePath = useBasePath() return ( = ({ tokens }) => { ) } -const TokenName: React.VFC = ({ token }) => { +function TokenName({ token }: RowProps) { return ( @@ -107,7 +106,7 @@ const TokenName: React.VFC = ({ token }) => { ) } -const AssetClass: React.VFC = ({ token }) => { +function AssetClass({ token }: RowProps) { const { data: metadata, isLoading } = usePoolMetadata({ id: token.poolId, metadata: token.poolMetadata }) return ( diff --git a/centrifuge-app/src/components/Tooltips.tsx b/centrifuge-app/src/components/Tooltips.tsx index 17af4b639f..1fc5d6e19b 100644 --- a/centrifuge-app/src/components/Tooltips.tsx +++ b/centrifuge-app/src/components/Tooltips.tsx @@ -3,9 +3,9 @@ import * as React from 'react' import { useParams } from 'react-router' import { usePool } from '../utils/usePools' -const ValueLockedTooltipBody: React.FC<{ poolId?: string }> = ({ poolId }) => { +function ValueLockedTooltipBody({ poolId }: { poolId?: string }) { const { pid: poolIdParam } = useParams<{ pid: string }>() - const pool = usePool(poolId || poolIdParam) + const pool = usePool(poolId || poolIdParam || '', false) return <>Value locked represents the current total value of pool tokens in {pool?.currency.symbol}. } @@ -323,13 +323,7 @@ export type TooltipsProps = { props?: any } & Partial> -export const Tooltips: React.FC = ({ - type, - label: labelOverride, - variant = 'primary', - props, - ...textProps -}) => { +export function Tooltips({ type, label: labelOverride, variant = 'primary', props, ...textProps }: TooltipsProps) { const { label, body } = type ? tooltipText[type] : { label: labelOverride, body: textProps.body } const isPrimary = variant === 'primary' return ( diff --git a/centrifuge-app/src/components/VisibilityChecker.tsx b/centrifuge-app/src/components/VisibilityChecker.tsx index baad2054b7..ee5b1d2a86 100644 --- a/centrifuge-app/src/components/VisibilityChecker.tsx +++ b/centrifuge-app/src/components/VisibilityChecker.tsx @@ -5,7 +5,7 @@ type Props = Omit & { children?: React.ReactNode } -export const VisibilityChecker: React.FC = ({ children, ...visibilityCheckerOptions }) => { +export function VisibilityChecker({ children, ...visibilityCheckerOptions }: Props) { const ref = React.useRef(null) useVisibilityChecker({ ref, ...visibilityCheckerOptions }) diff --git a/centrifuge-app/src/pages/AccountNFTs.tsx b/centrifuge-app/src/pages/AccountNFTs.tsx index 13fc1218b3..45092754b0 100644 --- a/centrifuge-app/src/pages/AccountNFTs.tsx +++ b/centrifuge-app/src/pages/AccountNFTs.tsx @@ -21,7 +21,7 @@ export default function AccountNFTsPage() { const COUNT_PER_PAGE = 16 -const AccountNFTs: React.FC = () => { +function AccountNFTs() { const address = useAddress('substrate') const nfts = useAccountNfts(address) const collections = useCollections() diff --git a/centrifuge-app/src/pages/Collection.tsx b/centrifuge-app/src/pages/Collection.tsx index 0d5203c729..fd5e1e7f41 100644 --- a/centrifuge-app/src/pages/Collection.tsx +++ b/centrifuge-app/src/pages/Collection.tsx @@ -31,7 +31,7 @@ export default function CollectionPage() { const COUNT_PER_PAGE = 16 -const Collection: React.FC = () => { +function Collection() { const { cid: collectionId } = useParams() const collection = useCollection(collectionId) diff --git a/centrifuge-app/src/pages/Collections.tsx b/centrifuge-app/src/pages/Collections.tsx index 4c633881e0..d159d66109 100644 --- a/centrifuge-app/src/pages/Collections.tsx +++ b/centrifuge-app/src/pages/Collections.tsx @@ -25,7 +25,7 @@ export default function CollectionsPage() { const COUNT_PER_PAGE = 12 -const Collections: React.FC = () => { +function Collections() { const [createOpen, setCreateOpen] = React.useState(false) const address = useAddress('substrate') const collections = useCollections() diff --git a/centrifuge-app/src/pages/IssuerCreatePool/IssuerInput.tsx b/centrifuge-app/src/pages/IssuerCreatePool/IssuerInput.tsx index d8d111971a..d0e3f7f9e9 100644 --- a/centrifuge-app/src/pages/IssuerCreatePool/IssuerInput.tsx +++ b/centrifuge-app/src/pages/IssuerCreatePool/IssuerInput.tsx @@ -1,6 +1,5 @@ import { Box, FileUpload, Grid, ImageUpload, Text, TextAreaInput, TextInput } from '@centrifuge/fabric' import { Field, FieldProps } from 'formik' -import * as React from 'react' import { FieldWithErrorMessage } from '../../components/FieldWithErrorMessage' import { Tooltips } from '../../components/Tooltips' import { isTestEnv } from '../../config' @@ -13,7 +12,7 @@ type Props = { const createLabel = (label: string) => `${label}${isTestEnv ? '' : '*'}` -export const IssuerInput: React.FC = ({ waitingForStoredIssuer = false }) => { +export function IssuerInput({ waitingForStoredIssuer = false }: Props) { return ( diff --git a/centrifuge-app/src/pages/IssuerCreatePool/PoolFeeInput.tsx b/centrifuge-app/src/pages/IssuerCreatePool/PoolFeeInput.tsx index d75ed57eb5..6ba2a0c109 100644 --- a/centrifuge-app/src/pages/IssuerCreatePool/PoolFeeInput.tsx +++ b/centrifuge-app/src/pages/IssuerCreatePool/PoolFeeInput.tsx @@ -40,7 +40,7 @@ const DEFAULT_FEE = { }, } -export const PoolFeeSection: React.FC = () => { +export function PoolFeeSection() { const fmk = useFormikContext() const { values } = fmk const address = useAddress() @@ -92,7 +92,7 @@ export const PoolFeeSection: React.FC = () => { ) } -export const PoolFeeInput: React.FC = () => { +export function PoolFeeInput() { const fmk = useFormikContext() const { values } = fmk diff --git a/centrifuge-app/src/pages/IssuerCreatePool/TrancheInput.tsx b/centrifuge-app/src/pages/IssuerCreatePool/TrancheInput.tsx index 46bfb5ea64..70177734d9 100644 --- a/centrifuge-app/src/pages/IssuerCreatePool/TrancheInput.tsx +++ b/centrifuge-app/src/pages/IssuerCreatePool/TrancheInput.tsx @@ -20,7 +20,7 @@ import { validate } from './validate' const MAX_TRANCHES = 3 -export const TrancheSection: React.FC = () => { +export function TrancheSection() { const fmk = useFormikContext() const { values, setFieldValue } = fmk @@ -74,11 +74,7 @@ export const TrancheSection: React.FC = () => { ) } -export const TrancheInput: React.FC<{ canRemove?: boolean; currency?: string; isUpdating?: boolean }> = ({ - canRemove, - currency, - isUpdating, -}) => { +export function TrancheInput({ canRemove, isUpdating }: { canRemove?: boolean; isUpdating?: boolean }) { const fmk = useFormikContext() const { values } = fmk diff --git a/centrifuge-app/src/pages/IssuerCreatePool/index.tsx b/centrifuge-app/src/pages/IssuerCreatePool/index.tsx index 6d8a7fd838..69ed4932ff 100644 --- a/centrifuge-app/src/pages/IssuerCreatePool/index.tsx +++ b/centrifuge-app/src/pages/IssuerCreatePool/index.tsx @@ -154,7 +154,7 @@ const initialValues: CreatePoolValues = { poolType: 'open', } -const PoolIcon: React.FC<{ icon?: File | null; children: string }> = ({ children, icon }) => { +function PoolIcon({ icon, children }: { icon?: File | null; children: string }) { const [uri, setUri] = React.useState('') React.useEffect(() => { ;(async () => { @@ -549,6 +549,7 @@ function CreatePoolForm() { if (form.values.poolName) { form.setFieldValue('tranches', [createEmptyTranche(form.values.poolName)]) } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [form.values.poolName]) return ( diff --git a/centrifuge-app/src/pages/IssuerPool/Assets/CreateLoan.tsx b/centrifuge-app/src/pages/IssuerPool/Assets/CreateLoan.tsx index 36aa97a260..0761235e64 100644 --- a/centrifuge-app/src/pages/IssuerPool/Assets/CreateLoan.tsx +++ b/centrifuge-app/src/pages/IssuerPool/Assets/CreateLoan.tsx @@ -165,6 +165,7 @@ function TemplateField({ label, name, input }: TemplateFieldProps) { function IssuerCreateLoan() { const { pid } = useParams<{ pid: string }>() + if (!pid) throw new Error('Pool not found') const pool = usePool(pid) const [redirect, setRedirect] = React.useState() const navigate = useNavigate() @@ -274,6 +275,17 @@ function IssuerCreateLoan() { notional: CurrencyBalance.fromFloat(values.pricing.notional, decimals), withLinearPricing: values.pricing.withLinearPricing, } + } else if (values.pricing.valuationMethod === 'outstandingDebt') { + pricingInfo = { + valuationMethod: values.pricing.valuationMethod, + maxBorrowAmount: values.pricing.maxBorrowAmount, + value: CurrencyBalance.fromFloat(values.pricing.value, decimals), + maturityDate: values.pricing.maturity !== 'none' ? new Date(values.pricing.maturityDate) : null, + maturityExtensionDays: + values.pricing.maturity === 'fixedWithExtension' ? values.pricing.maturityExtensionDays : null, + advanceRate: Rate.fromPercent(values.pricing.advanceRate), + interestRate: Rate.fromPercent(values.pricing.interestRate), + } } else { pricingInfo = { valuationMethod: values.pricing.valuationMethod, diff --git a/centrifuge-app/src/pages/IssuerPool/Configuration/ViewLoanTemplate.tsx b/centrifuge-app/src/pages/IssuerPool/Configuration/ViewLoanTemplate.tsx index 2aa732df3b..1ea24d3f46 100644 --- a/centrifuge-app/src/pages/IssuerPool/Configuration/ViewLoanTemplate.tsx +++ b/centrifuge-app/src/pages/IssuerPool/Configuration/ViewLoanTemplate.tsx @@ -15,6 +15,7 @@ export function IssuerPoolViewLoanTemplatePage() { export function ViewLoanTemplate() { const { pid: poolId, sid: templateId } = useParams<{ pid: string; sid: string }>() + if (!poolId || !templateId) throw new Error('Template not found') const pool = usePool(poolId) const { data: poolMetadata } = usePoolMetadata(pool) const { data: templateData } = useMetadata(`ipfs://${templateId}`) diff --git a/centrifuge-app/src/pages/IssuerPool/Configuration/WriteOffInput.tsx b/centrifuge-app/src/pages/IssuerPool/Configuration/WriteOffInput.tsx index a20bc50114..f2cddc699c 100644 --- a/centrifuge-app/src/pages/IssuerPool/Configuration/WriteOffInput.tsx +++ b/centrifuge-app/src/pages/IssuerPool/Configuration/WriteOffInput.tsx @@ -5,7 +5,7 @@ import { FieldWithErrorMessage } from '../../../components/FieldWithErrorMessage import { validate } from '../../IssuerCreatePool/validate' import { WriteOffGroupValues } from './WriteOffGroups' -export const WriteOffInput: React.FC = () => { +export function WriteOffInput() { const fmk = useFormikContext() const { values } = fmk diff --git a/centrifuge-app/src/pages/IssuerPool/Header.tsx b/centrifuge-app/src/pages/IssuerPool/Header.tsx index 7215beca55..e484bf85bb 100644 --- a/centrifuge-app/src/pages/IssuerPool/Header.tsx +++ b/centrifuge-app/src/pages/IssuerPool/Header.tsx @@ -16,6 +16,7 @@ type Props = { export function IssuerHeader({ actions, children }: Props) { const { pid } = useParams<{ pid: string }>() + if (!pid) throw new Error('Pool not found') const pool = usePool(pid) const { data: metadata, isLoading } = usePoolMetadata(pool) const cent = useCentrifuge() @@ -65,6 +66,7 @@ export function IssuerHeader({ actions, children }: Props) { export function IssuerPoolHeader({ actions }: Props) { const { pid } = useParams<{ pid: string }>() + if (!pid) throw new Error('Pool not found') const pool = usePool(pid) const basePath = useBasePath() const isTinlakePool = pool.id.startsWith('0x') diff --git a/centrifuge-app/src/pages/IssuerPool/Investors/InvestorStatus.tsx b/centrifuge-app/src/pages/IssuerPool/Investors/InvestorStatus.tsx index d806e66f80..9fbc493129 100644 --- a/centrifuge-app/src/pages/IssuerPool/Investors/InvestorStatus.tsx +++ b/centrifuge-app/src/pages/IssuerPool/Investors/InvestorStatus.tsx @@ -81,13 +81,16 @@ export function InvestorStatus() { const domains = chain ? [[chain, validAddress]] : undefined if (isAllowed) { - execute([poolId, [], [[centAddress, { TrancheInvestor: [trancheId, SevenDaysFromNow, domains as any] }]]], { + execute([poolId!, [], [[centAddress, { TrancheInvestor: [trancheId, SevenDaysFromNow, domains as any] }]]], { account, }) } else { - execute([poolId, [[centAddress, { TrancheInvestor: [trancheId, OneHundredYearsFromNow, domains as any] }]], []], { - account, - }) + execute( + [poolId!, [[centAddress, { TrancheInvestor: [trancheId, OneHundredYearsFromNow, domains as any] }]], []], + { + account, + } + ) } setPendingTrancheId(trancheId) } @@ -191,11 +194,7 @@ export function InvestorStatus() { ) } -const InvestedCell: React.FC<{ address: string; poolId: string; trancheId: string }> = ({ - poolId, - trancheId, - address, -}) => { +function InvestedCell({ address, poolId, trancheId }: { address: string; poolId: string; trancheId: string }) { const order = useOrder(poolId, trancheId, address) const balances = useBalances(address) const hasBalance = balances && findBalance(balances.tranches, { Tranche: [poolId, trancheId] }) diff --git a/centrifuge-app/src/pages/IssuerPool/Pricing/OracleFeeders.tsx b/centrifuge-app/src/pages/IssuerPool/Pricing/OracleFeeders.tsx index 9c264723fa..c141a87962 100644 --- a/centrifuge-app/src/pages/IssuerPool/Pricing/OracleFeeders.tsx +++ b/centrifuge-app/src/pages/IssuerPool/Pricing/OracleFeeders.tsx @@ -91,6 +91,7 @@ export function OracleFeeders({ poolId }: { poolId: string }) { if (form.values.feeders.length > 0 && form.values.minFeeders === 0) { form.setFieldValue('minFeeders', 1) } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [form.values.feeders, form.values.minFeeders, form.setFieldValue]) const rows = React.useMemo(() => form.values.feeders.map((a, i) => ({ address: a, index: i })), [form.values.feeders]) diff --git a/centrifuge-app/src/pages/Loan/FinancingRepayment.tsx b/centrifuge-app/src/pages/Loan/FinancingRepayment.tsx deleted file mode 100644 index 1e3eaae94c..0000000000 --- a/centrifuge-app/src/pages/Loan/FinancingRepayment.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import * as React from 'react' -import { LabelValueStack } from '../../components/LabelValueStack' - -export const FinancingRepayment: React.FC<{ - drawDownDate: string | null - closingDate: string | null - outstandingPrincipal: string - outstandingInterest: string - repaidPrincipal: string - repaidInterest: string - repaidUnscheduled: string | null -}> = ({ - drawDownDate, - closingDate, - outstandingPrincipal, - outstandingInterest, - repaidPrincipal, - repaidInterest, - repaidUnscheduled, -}) => { - return ( - <> - {!!drawDownDate && } - {!!closingDate && } - - - - - {!!repaidUnscheduled && } - - ) -} diff --git a/centrifuge-app/src/pages/Loan/HoldingsValues.tsx b/centrifuge-app/src/pages/Loan/HoldingsValues.tsx index 290d84c5be..8f9146f16a 100644 --- a/centrifuge-app/src/pages/Loan/HoldingsValues.tsx +++ b/centrifuge-app/src/pages/Loan/HoldingsValues.tsx @@ -51,7 +51,7 @@ export function HoldingsValues({ pool, transactions, currentFace, pricing }: Pro ) return weightedSum.div(sumOfAmounts) - }, [transactions]) + }, [pool.currency.decimals, transactions]) const metrics = [ ...(pricing.notional.gtn(0) diff --git a/centrifuge-app/src/pages/Loan/KeyMetrics.tsx b/centrifuge-app/src/pages/Loan/KeyMetrics.tsx index 08e11508b5..1369ddacc2 100644 --- a/centrifuge-app/src/pages/Loan/KeyMetrics.tsx +++ b/centrifuge-app/src/pages/Loan/KeyMetrics.tsx @@ -7,6 +7,7 @@ import { LoanTemplate } from '../../types' import { Dec } from '../../utils/Decimal' import { daysBetween, formatDate, isValidDate } from '../../utils/date' import { formatBalance, formatPercentage } from '../../utils/formatting' +import { TinlakePool } from '../../utils/tinlake/useTinlakePools' import { useMetadata } from '../../utils/useMetadata' import { useCentNFT } from '../../utils/useNFTs' import { useBorrowerAssetTransactions, usePoolMetadata } from '../../utils/usePools' @@ -17,7 +18,7 @@ type Props = { loan: Loan | TinlakeLoan } -export const KeyMetrics = ({ pool, loan }: Props) => { +export function KeyMetrics({ pool, loan }: Props) { const { data: poolMetadata } = usePoolMetadata(pool) const borrowerAssetTransactions = useBorrowerAssetTransactions(pool.id, loan.id) @@ -26,7 +27,7 @@ export const KeyMetrics = ({ pool, loan }: Props) => { const { data: templateMetadata } = useMetadata(templateId) const nft = useCentNFT(loan?.asset.collectionId, loan?.asset.nftId, false) - const { data: nftMetadata, isLoading: nftMetadataIsLoading } = useMetadata(nft?.metadataUri, nftMetadataSchema) + const { data: nftMetadata } = useMetadata(nft?.metadataUri, nftMetadataSchema) const currentFace = loan?.pricing && 'outstandingQuantity' in loan.pricing @@ -126,14 +127,18 @@ export const KeyMetrics = ({ pool, loan }: Props) => { loan.pricing.valuationMethod === 'oracle' && loan.pricing.notional.gtn(0) ? [ - sumRealizedProfitFifo && { - label: 'Realized P&L', - value: formatBalance(sumRealizedProfitFifo, pool.currency.symbol), - }, - unrealizedProfitAtMarketPrice && { - label: 'Unrealized P&L', - value: formatBalance(unrealizedProfitAtMarketPrice, pool.currency.symbol), - }, + sumRealizedProfitFifo + ? { + label: 'Realized P&L', + value: formatBalance(sumRealizedProfitFifo, pool.currency.symbol), + } + : (null as never), + unrealizedProfitAtMarketPrice + ? { + label: 'Unrealized P&L', + value: formatBalance(unrealizedProfitAtMarketPrice, pool.currency.symbol), + } + : (null as never), ].filter(Boolean) : []), ...(loan.pricing.maturityDate && diff --git a/centrifuge-app/src/pages/Loan/MetricsTable.tsx b/centrifuge-app/src/pages/Loan/MetricsTable.tsx index 03dbef282a..431ebc3425 100644 --- a/centrifuge-app/src/pages/Loan/MetricsTable.tsx +++ b/centrifuge-app/src/pages/Loan/MetricsTable.tsx @@ -2,8 +2,8 @@ import { AnchorTextLink } from '@centrifuge/centrifuge-app/src/components/TextLi import { Box, Grid, Text } from '@centrifuge/fabric' type Metric = { - label: string - value: string + label: React.ReactNode + value: string | undefined } type Props = { diff --git a/centrifuge-app/src/pages/Loan/TransactionTable.tsx b/centrifuge-app/src/pages/Loan/TransactionTable.tsx index 889d4a53bc..eb0071f065 100644 --- a/centrifuge-app/src/pages/Loan/TransactionTable.tsx +++ b/centrifuge-app/src/pages/Loan/TransactionTable.tsx @@ -122,7 +122,7 @@ export const TransactionTable = ({ realizedProfitFifo: transaction.realizedProfitFifo, } }) - }, [transactions, decimals, pricing]) + }, [transactions, maturityDate, pricing, decimals]) const getStatusChipType = (type: AssetTransactionType) => { if (type === 'BORROWED' || type === 'CREATED' || type === 'PRICED') return 'info' @@ -137,93 +137,89 @@ export const TransactionTable = ({ return `${type[0]}${type.slice(1).toLowerCase()}` } - const columns = useMemo(() => { - return [ - { - align: 'left', - header: 'Type', - cell: (row: Row) => {getStatusText(row.type)}, - }, - { - align: 'left', - header: 'Transaction date', - cell: (row: Row) => ( - - {formatDate(row.transactionDate)} - - ), - }, - ...(poolType === 'Public credit' - ? [ - { - align: 'left', - header: `Face value (${currency})`, - cell: (row: Row) => - row.faceValue - ? `${row.type === 'REPAID' ? '-' : ''}${formatBalance(row.faceValue, undefined, 2, 2)}` - : '-', - }, - { - align: 'left', - header: 'Quantity', - cell: (row: Row) => (row.quantity ? formatBalance(row.quantity, undefined, 2, 0) : '-'), - }, - { - align: 'left', - header: `Settle price (${currency})`, - cell: (row: Row) => (row.settlePrice ? formatBalance(row.settlePrice, undefined, 6, 2) : '-'), - }, - ...(loanType === 'external' && (pricing as ExternalPricingInfo).notional.gtn(0) - ? [ - { - align: 'left', - header: , - cell: (row: Row) => - !row.yieldToMaturity || row.yieldToMaturity?.lt(0) ? '-' : formatPercentage(row.yieldToMaturity), - }, - ] - : []), - { - align: 'left', - header: `Net cash flow (${currency})`, - cell: (row: Row) => - row.amount ? `${row.type === 'BORROWED' ? '-' : ''}${formatBalance(row.amount, undefined, 2, 2)}` : '-', - }, - { - align: 'left', - header: `Realized P&L`, - cell: (row: Row) => - row.realizedProfitFifo - ? `${row.type !== 'REPAID' ? '-' : ''}${formatBalance(row.realizedProfitFifo, undefined, 2, 2)}` - : '-', - }, - { - align: 'left', - header: `Position (${currency})`, - cell: (row: Row) => (row.type === 'CREATED' ? '-' : formatBalance(row.position, undefined, 2, 2)), - }, - ] - : [ - { - align: 'left', - header: `Amount (${currency})`, - cell: (row: Row) => - row.amount ? `${row.type === 'REPAID' ? '-' : ''}${formatBalance(row.amount, undefined, 2, 2)}` : '-', - }, - { - align: 'left', - header: `Principal (${currency})`, - cell: (row: Row) => - row.position - ? `${row.type === 'REPAID' ? '-' : ''}${formatBalance(row.position, undefined, 2, 2)}` - : '-', - }, - ]), - ] as Column[] - }, []) + const columns = [ + { + align: 'left', + header: 'Type', + cell: (row: Row) => {getStatusText(row.type)}, + }, + { + align: 'left', + header: 'Transaction date', + cell: (row: Row) => ( + + {formatDate(row.transactionDate)} + + ), + }, + ...(poolType === 'Public credit' + ? [ + { + align: 'left', + header: `Face value (${currency})`, + cell: (row: Row) => + row.faceValue + ? `${row.type === 'REPAID' ? '-' : ''}${formatBalance(row.faceValue, undefined, 2, 2)}` + : '-', + }, + { + align: 'left', + header: 'Quantity', + cell: (row: Row) => (row.quantity ? formatBalance(row.quantity, undefined, 2, 0) : '-'), + }, + { + align: 'left', + header: `Settle price (${currency})`, + cell: (row: Row) => (row.settlePrice ? formatBalance(row.settlePrice, undefined, 6, 2) : '-'), + }, + ...(loanType === 'external' && (pricing as ExternalPricingInfo).notional.gtn(0) + ? [ + { + align: 'left', + header: , + cell: (row: Row) => + !row.yieldToMaturity || row.yieldToMaturity?.lt(0) ? '-' : formatPercentage(row.yieldToMaturity), + }, + ] + : []), + { + align: 'left', + header: `Net cash flow (${currency})`, + cell: (row: Row) => + row.amount ? `${row.type === 'BORROWED' ? '-' : ''}${formatBalance(row.amount, undefined, 2, 2)}` : '-', + }, + { + align: 'left', + header: `Realized P&L`, + cell: (row: Row) => + row.realizedProfitFifo + ? `${row.type !== 'REPAID' ? '-' : ''}${formatBalance(row.realizedProfitFifo, undefined, 2, 2)}` + : '-', + }, + { + align: 'left', + header: `Position (${currency})`, + cell: (row: Row) => (row.type === 'CREATED' ? '-' : formatBalance(row.position, undefined, 2, 2)), + }, + ] + : [ + { + align: 'left', + header: `Amount (${currency})`, + cell: (row: Row) => + row.amount ? `${row.type === 'REPAID' ? '-' : ''}${formatBalance(row.amount, undefined, 2, 2)}` : '-', + }, + { + align: 'left', + header: `Principal (${currency})`, + cell: (row: Row) => + row.position ? `${row.type === 'REPAID' ? '-' : ''}${formatBalance(row.position, undefined, 2, 2)}` : '-', + }, + ]), + ] as Column[] return } diff --git a/centrifuge-app/src/pages/Loan/index.tsx b/centrifuge-app/src/pages/Loan/index.tsx index cff9500434..d418300b68 100644 --- a/centrifuge-app/src/pages/Loan/index.tsx +++ b/centrifuge-app/src/pages/Loan/index.tsx @@ -112,6 +112,7 @@ function FinanceButton({ loan }: { loan: LoanType }) { function Loan() { const theme = useTheme() const { pid: poolId, aid: loanId } = useParams<{ pid: string; aid: string }>() + if (!poolId || !loanId) throw new Error('Loan no found') const isTinlakePool = poolId?.startsWith('0x') const basePath = useBasePath() const pool = usePool(poolId) @@ -293,7 +294,7 @@ function Loan() { poolType={poolMetadata?.pool?.asset.class} decimals={pool.currency.decimals} pricing={loan.pricing as PricingInfo} - maturityDate={new Date(loan.pricing.maturityDate)} + maturityDate={loan.pricing.maturityDate ? new Date(loan.pricing.maturityDate) : undefined} originationDate={originationDate ? new Date(originationDate) : undefined} /> diff --git a/centrifuge-app/src/pages/MintNFT.tsx b/centrifuge-app/src/pages/MintNFT.tsx index 573f33d698..d9ba6944dc 100644 --- a/centrifuge-app/src/pages/MintNFT.tsx +++ b/centrifuge-app/src/pages/MintNFT.tsx @@ -1,22 +1,10 @@ import { NFTMetadataInput } from '@centrifuge/centrifuge-js/dist/modules/nfts' import { useAsyncCallback, useBalances, useCentrifuge, useCentrifugeTransaction } from '@centrifuge/centrifuge-react' -import { - Box, - Button, - Grid, - ImageUpload, - NumberInput, - Shelf, - Stack, - Text, - TextAreaInput, - TextInput, -} from '@centrifuge/fabric' +import { Box, Button, Grid, ImageUpload, Shelf, Stack, Text, TextAreaInput, TextInput } from '@centrifuge/fabric' import * as React from 'react' import { useNavigate, useParams } from 'react-router' import { lastValueFrom } from 'rxjs' import { ButtonGroup } from '../components/ButtonGroup' -import { useDebugFlags } from '../components/DebugFlags' import { LayoutBase } from '../components/LayoutBase' import { PageHeader } from '../components/PageHeader' import { PageSection } from '../components/PageSection' @@ -53,8 +41,9 @@ export default function MintNFTPage() { ) } -const MintNFT: React.FC = () => { +function MintNFT() { const { cid: collectionId } = useParams<{ cid: string }>() + if (!collectionId) throw new Error('Collection not found') const collection = useCollection(collectionId) const { data: collectionMetadata } = useCollectionMetadata(collectionId) @@ -66,7 +55,6 @@ const MintNFT: React.FC = () => { const navigate = useNavigate() const [nftName, setNftName] = React.useState('') - const [nftAmount, setNftAmount] = React.useState(1) const [nftDescription, setNftDescription] = React.useState('') const [fileDataUri, setFileDataUri] = React.useState('') const [file, setFile] = React.useState(null) @@ -112,7 +100,7 @@ const MintNFT: React.FC = () => { description: descriptionValue, image: imageMetadataHash.uri, } - doTransaction([collectionId, nftId, collection.owner, metadataValues, nftAmount], { account }) + doTransaction([collectionId, nftId, collection.owner, metadataValues], { account }) }) function reset() { @@ -133,8 +121,6 @@ const MintNFT: React.FC = () => { const fieldDisabled = balanceLow || !canMint || isMinting const submitDisabled = !isFormValid || balanceLow || !canMint || isMinting - const batchMintNFTs = useDebugFlags().batchMintNFTs - return (
@@ -184,21 +170,6 @@ const MintNFT: React.FC = () => { }} disabled={fieldDisabled} /> - {batchMintNFTs && ( - - { - setNftAmount(Number((target as HTMLInputElement).value)) - }} - disabled={fieldDisabled} - /> - - )} diff --git a/centrifuge-app/src/pages/NFT.tsx b/centrifuge-app/src/pages/NFT.tsx index 05401cf28a..3fd40d9e60 100644 --- a/centrifuge-app/src/pages/NFT.tsx +++ b/centrifuge-app/src/pages/NFT.tsx @@ -2,9 +2,6 @@ import { useCentrifuge } from '@centrifuge/centrifuge-react' import { Box, Button, IconArrowRight, IconNft, Shelf, Stack, Text, TextWithPlaceholder } from '@centrifuge/fabric' import * as React from 'react' import { useParams } from 'react-router-dom' -import { BuyDialog } from '../components/BuyDialog' -import { RemoveListingDialog } from '../components/Dialogs/RemoveListingDialog' -import { SellDialog } from '../components/Dialogs/SellDialog' import { TransferDialog } from '../components/Dialogs/TransferDialog' import { Identity } from '../components/Identity' import { LayoutBase } from '../components/LayoutBase' @@ -26,17 +23,15 @@ export default function NFTPage() { ) } -const NFT: React.FC = () => { +function NFT() { const { cid: collectionId, nftid: nftId } = useParams<{ cid: string; nftid: string }>() + if (!collectionId || !nftId) throw new Error('NFT not found') const address = useAddress('substrate') const nft = useCentNFT(collectionId, nftId) const { data: nftMetadata, isLoading } = useMetadata(nft?.metadataUri, nftMetadataSchema) const collection = useCollection(collectionId) const { data: collectionMetadata } = useCollectionMetadata(collection?.id) const [transferOpen, setTransferOpen] = React.useState(false) - const [sellOpen, setSellOpen] = React.useState(false) - const [buyOpen, setBuyOpen] = React.useState(false) - const [unlistOpen, setUnlistOpen] = React.useState(false) const centrifuge = useCentrifuge() const imageUrl = nftMetadata?.image ? centrifuge.metadata.parseMetadataUrl(nftMetadata.image) : '' @@ -132,13 +127,6 @@ const NFT: React.FC = () => { - - {nft.sellPrice !== null && ( - - Price - {centrifuge.utils.formatCurrencyAmount(nft.sellPrice, 'AIR')} - - )} )} @@ -147,22 +135,7 @@ const NFT: React.FC = () => { address && (isSameAddress(nft.owner, address) ? ( <> - {nft.sellPrice !== null ? ( - - ) : ( - - )} - { open={transferOpen} onClose={() => setTransferOpen(false)} /> - setSellOpen(false)} - /> - setBuyOpen(false)} - /> - setUnlistOpen(false)} - /> - - ) : ( - <> - {nft.sellPrice !== null && ( - - )} - setBuyOpen(false)} - /> - ))} + ) : null)} diff --git a/centrifuge-app/src/pages/NavManagement/Overview.tsx b/centrifuge-app/src/pages/NavManagement/Overview.tsx index a6bf197615..586a10fffc 100644 --- a/centrifuge-app/src/pages/NavManagement/Overview.tsx +++ b/centrifuge-app/src/pages/NavManagement/Overview.tsx @@ -14,6 +14,7 @@ import { NavManagementAssetTable } from './NavManagementAssetTable' export default function NavManagementOverviewPage() { const { pid } = useParams<{ pid: string }>() + if (!pid) throw new Error('Pool not found') return ( @@ -101,7 +102,7 @@ export function NavOverviewCard({ poolId }: { poolId: string }) { return lastUpdatedSumBorrowedAmountByPeriod && todaySumBorrowedAmountByPeriod ? new BN(todaySumBorrowedAmountByPeriod).sub(new BN(lastUpdatedSumBorrowedAmountByPeriod)) : new BN(0) - }, [dailyPoolStates]) + }, [dailyPoolStates, pool?.nav.lastUpdated]) return ( { +function Pools() { const location = useLocation() return ( diff --git a/centrifuge-app/src/pages/Onboarding/TaxInfo.tsx b/centrifuge-app/src/pages/Onboarding/TaxInfo.tsx index 70750ad88b..6db9c91b80 100644 --- a/centrifuge-app/src/pages/Onboarding/TaxInfo.tsx +++ b/centrifuge-app/src/pages/Onboarding/TaxInfo.tsx @@ -24,6 +24,7 @@ export const TaxInfo = ({ value, setValue, touched, error }: TaxInfoProps) => { if (uploadNewFile) { setValue(null) } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [uploadNewFile, taxInfoData]) const isCompleted = !!onboardingUser.taxDocument diff --git a/centrifuge-app/src/pages/Pool/Header.tsx b/centrifuge-app/src/pages/Pool/Header.tsx index 2f2bfc47aa..8c6eba054d 100644 --- a/centrifuge-app/src/pages/Pool/Header.tsx +++ b/centrifuge-app/src/pages/Pool/Header.tsx @@ -14,10 +14,11 @@ type Props = { actions?: React.ReactNode } -export const PoolDetailHeader: React.FC = ({ actions }) => { +export function PoolDetailHeader({ actions }: Props) { const { pid } = useParams<{ pid: string }>() + if (!pid) throw new Error('Pool not foud') const basePath = useBasePath() - const { state } = useLocation<{ token: string }>() + const { state } = useLocation() const pool = usePool(pid) const { data: metadata, isLoading } = usePoolMetadata(pool) const isTinlakePool = pool.id.startsWith('0x') diff --git a/centrifuge-app/src/pages/Pool/Liquidity/index.tsx b/centrifuge-app/src/pages/Pool/Liquidity/index.tsx index e38e4721a1..93c004b568 100644 --- a/centrifuge-app/src/pages/Pool/Liquidity/index.tsx +++ b/centrifuge-app/src/pages/Pool/Liquidity/index.tsx @@ -13,7 +13,6 @@ import { useSuitableAccounts } from '../../../utils/usePermissions' import { usePool } from '../../../utils/usePools' import { PoolDetailHeader } from '../Header' -const CashDragChart = React.lazy(() => import('../../../components/Charts/CashDragChart')) const LiquidityTransactionsSection = React.lazy(() => import('../../../components/LiquidityTransactionsSection')) export function PoolDetailLiquidityTab() { diff --git a/centrifuge-app/src/utils/tinlake/useTinlakePools.ts b/centrifuge-app/src/utils/tinlake/useTinlakePools.ts index 33dd00867e..2dec045cb2 100644 --- a/centrifuge-app/src/utils/tinlake/useTinlakePools.ts +++ b/centrifuge-app/src/utils/tinlake/useTinlakePools.ts @@ -713,6 +713,10 @@ async function getPools(pools: IpfsPools): Promise<{ pools: TinlakePool[] }> { lastUpdated: new Date().toISOString(), total: data.netAssetValue, aum: data.netAssetValue, + fees: new CurrencyBalance(0, 18), + }, + fees: { + totalPaid: new CurrencyBalance(0, 18), }, createdAt: null, isInitialised: true, diff --git a/centrifuge-app/src/utils/tinlake/useTinlakePortfolio.ts b/centrifuge-app/src/utils/tinlake/useTinlakePortfolio.ts index 5eafdfec42..f12f5561bf 100644 --- a/centrifuge-app/src/utils/tinlake/useTinlakePortfolio.ts +++ b/centrifuge-app/src/utils/tinlake/useTinlakePortfolio.ts @@ -83,7 +83,7 @@ async function getTinlakePortfolio(ipfsPools: IpfsPools, address: string) { const tokenBalances = Object.entries(updatesPerToken).map(([tokenId, tokenResult]) => { let tranche = TinlakeTranche.senior - ipfsPools.active.flatMap((pool) => { + ipfsPools.active.forEach((pool) => { if (tokenId === pool.addresses.JUNIOR_TOKEN) { tranche = TinlakeTranche.junior } diff --git a/centrifuge-app/src/utils/useAverageMaturity.ts b/centrifuge-app/src/utils/useAverageMaturity.ts index 2e03e76e1c..c72a5b36b7 100644 --- a/centrifuge-app/src/utils/useAverageMaturity.ts +++ b/centrifuge-app/src/utils/useAverageMaturity.ts @@ -10,7 +10,7 @@ export const useAverageMaturity = (poolId: string) => { const avgMaturity = React.useMemo(() => { const assets = (loans && [...loans].filter((asset) => asset.status === 'Active')) as ActiveLoan[] const maturityPerAsset = assets.reduce((sum, asset) => { - if ('maturityDate' in asset.pricing && asset.pricing.valuationMethod !== 'cash') { + if ('maturityDate' in asset.pricing && asset.pricing.maturityDate && asset.pricing.valuationMethod !== 'cash') { return sum.add( Dec(daysBetween(asset.originationDate, asset.pricing.maturityDate)).mul(asset.outstandingDebt.toDecimal()) ) diff --git a/centrifuge-app/src/utils/useLinkIsActive.ts b/centrifuge-app/src/utils/useLinkIsActive.ts deleted file mode 100644 index cf3fadaffd..0000000000 --- a/centrifuge-app/src/utils/useLinkIsActive.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Location } from 'history' -import { NavLinkProps, matchPath, useLocation } from 'react-router-dom' - -type Params = Pick & { exact?: boolean; strict?: boolean } - -export function useLinkIsActive({ - to, - location: locationOverride, - isActive: isActiveCb, - exact = false, - strict = false, -}: Params) { - const location = useLocation() - const currentLocation = locationOverride || location - const toLocation = normalizeToLocation(resolveToLocation(to, currentLocation), currentLocation) - - const { pathname: path } = toLocation - // Regex taken from: https://github.com/pillarjs/path-to-regexp/blob/master/index.js#L202 - const escapedPath = path && path.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1') - - const match = escapedPath - ? matchPath( - { - path: escapedPath, - end: exact, // Use `end` instead of `exact` for strict matching - caseSensitive: false, // Use `caseSensitive` instead of `sensitive` - }, - currentLocation.pathname - ) - : null - - const isActive = !!(isActiveCb ? isActiveCb(match, currentLocation) : match) - - return isActive -} - -function resolveToLocation(to: Params['to'], currentLocation: Location) { - return typeof to === 'function' ? to(currentLocation) : to -} - -function normalizeToLocation(to: string | Partial, currentLocation: Location): Location { - if (typeof to === 'string') { - return { - ...currentLocation, - pathname: to, - } - } - return to as Location -} diff --git a/centrifuge-app/src/utils/useTransactionFeeEstimate.ts b/centrifuge-app/src/utils/useTransactionFeeEstimate.ts index 36b51a1507..b250bb4977 100644 --- a/centrifuge-app/src/utils/useTransactionFeeEstimate.ts +++ b/centrifuge-app/src/utils/useTransactionFeeEstimate.ts @@ -44,6 +44,7 @@ export function useTransactionFeeEstimate>( const signer = selectedAccount?.signer || provider await doTransaction(address, signer, args, options) }, + // eslint-disable-next-line react-hooks/exhaustive-deps [doTransaction, selectedAccount, address] ) diff --git a/centrifuge-app/src/utils/validation/index.ts b/centrifuge-app/src/utils/validation/index.ts index c4b34b3bca..93a4f26463 100644 --- a/centrifuge-app/src/utils/validation/index.ts +++ b/centrifuge-app/src/utils/validation/index.ts @@ -143,7 +143,7 @@ const calcISINCheck = (code: string) => { } // group by odd and even, multiply digits from group containing rightmost character by 2 for (let i = 0; i < conv.length; i++) { - digits += (parseInt(conv[i]) * (i % 2 == (conv.length % 2 != 0 ? 0 : 1) ? 2 : 1)).toString() + digits += (parseInt(conv[i]) * (i % 2 === (conv.length % 2 !== 0 ? 0 : 1) ? 2 : 1)).toString() } // sum all digits for (let i = 0; i < digits.length; i++) { diff --git a/centrifuge-js/src/modules/nfts.ts b/centrifuge-js/src/modules/nfts.ts index eea5d9d998..c245ba5094 100644 --- a/centrifuge-js/src/modules/nfts.ts +++ b/centrifuge-js/src/modules/nfts.ts @@ -1,6 +1,5 @@ import { StorageKey, u32 } from '@polkadot/types' -import BN from 'bn.js' -import { EMPTY, combineLatest, firstValueFrom, of } from 'rxjs' +import { EMPTY, combineLatest, firstValueFrom } from 'rxjs' import { expand, filter, map, repeatWhen, switchMap, take } from 'rxjs/operators' import { Centrifuge } from '../Centrifuge' import { TransactionOptions } from '../types' @@ -14,7 +13,6 @@ export type NFT = Item & { id: string collectionId: string metadataUri?: string - sellPrice: string | null } type Class = { @@ -135,21 +133,15 @@ export function getNftsModule(inst: Centrifuge) { combineLatest([ api.query.uniques.instanceMetadataOf.entries(collectionId), api.query.uniques.asset.entries(collectionId), - api.query.nftSales.sales.entries(collectionId), ]) ), - map(([metas, nfts, sales]) => { + map(([metas, nfts]) => { const metasObj = metas.reduce((acc, [keys, value]) => { // @ts-expect-error acc[formatItemKey(keys)] = value.toHuman() return acc }, {} as any) - const salesObj = sales.reduce((acc, [keys, value]) => { - acc[formatItemKey(keys as StorageKey<[u32, u32]>)] = value.toJSON() - return acc - }, {} as any) - const mapped = nfts.map(([keys, value]) => { // @ts-expect-error const id = formatItemKey(keys) @@ -157,9 +149,8 @@ export function getNftsModule(inst: Centrifuge) { const nft: NFT = { id, collectionId, - owner: salesObj[id]?.seller || nftValue.owner, + owner: nftValue.owner, metadataUri: metasObj[id]?.data, - sellPrice: salesObj[id]?.seller ? parseHex(salesObj[id]?.price.amount) : null, } return nft }) @@ -178,19 +169,16 @@ export function getNftsModule(inst: Centrifuge) { combineLatest([ api.query.uniques.instanceMetadataOf(collectionId, nftId), api.query.uniques.asset(collectionId, nftId), - api.query.nftSales?.sales(collectionId, nftId) ?? of(null), ]) ), - map(([meta, nftData, sale]) => { + map(([meta, nftData]) => { const nftValue = nftData.toJSON() as Item - const saleValue = sale?.toJSON() as any if (!nftValue) throw new Error(`NFT not found: collectionId: ${collectionId}, nftId: ${nftId}`) const nft: NFT = { id: nftId, collectionId, - owner: addressToHex(saleValue?.seller || nftValue.owner), + owner: addressToHex(nftValue.owner), metadataUri: (meta.toHuman() as any)?.data, - sellPrice: saleValue ? parseHex(saleValue.price.amount) : null, } return nft }) @@ -216,40 +204,30 @@ export function getNftsModule(inst: Centrifuge) { return $api.pipe( switchMap( - (api) => - combineLatest([api.query.uniques.account.keys(address), api.query.nftSales.nftsBySeller.keys(address)]), - (api, [accountKeys, salesKeys]) => ({ + (api) => combineLatest([api.query.uniques.account.keys(address)]), + (api, [accountKeys]) => ({ api, accountKeys, - salesKeys, }) ), - switchMap(({ api, accountKeys, salesKeys }) => { - const accountkeysArr = accountKeys.map((k) => { + switchMap(({ api, accountKeys }) => { + const keysArr = accountKeys.map((k) => { const [, cid, nid] = k.toHuman() as any return [cid.replace(/\D/g, ''), nid.replace(/\D/g, '')] }) - const salesKeysArr = salesKeys.map((k) => { - const [, cid, nid] = k.toHuman() as any - return [cid.replace(/\D/g, ''), nid.replace(/\D/g, '')] - }) - const keysArr = salesKeysArr.concat(accountkeysArr) return combineLatest([ api.query.uniques.instanceMetadataOf.multi(keysArr), api.query.uniques.asset.multi(keysArr), - api.query.nftSales.sales.multi(salesKeysArr), ]).pipe( - map(([metas, nfts, sales]) => { + map(([metas, nfts]) => { const mapped = nfts.map((value, i) => { const [collectionId, id] = keysArr[i] const instance = value.toJSON() as Item - const sale = sales[i]?.toJSON() as any const nft: NFT = { id, collectionId, - owner: addressToHex(sale?.seller || instance.owner), + owner: addressToHex(instance.owner), metadataUri: (metas[i]?.toHuman() as any)?.data, - sellPrice: sale ? parseHex(sale.price.amount) : null, } return nft }) @@ -330,42 +308,6 @@ export function getNftsModule(inst: Centrifuge) { ) } - function sellNft(args: [collectionId: string, nftId: string, price: BN], options?: TransactionOptions) { - const [collectionId, nftId, price] = args - const $api = inst.getApi() - return $api.pipe( - map((api) => ({ - api, - submittable: api.tx.nftSales.add(collectionId, nftId, ['Native', price.toString()]), - })), - switchMap(({ api, submittable }) => inst.wrapSignAndSend(api, submittable, options)) - ) - } - - function removeNftListing(args: [collectionId: string, nftId: string], options?: TransactionOptions) { - const [collectionId, nftId] = args - const $api = inst.getApi() - return $api.pipe( - map((api) => ({ - api, - submittable: api.tx.nftSales.remove(collectionId, nftId), - })), - switchMap(({ api, submittable }) => inst.wrapSignAndSend(api, submittable, options)) - ) - } - - function buyNft(args: [collectionId: string, nftId: string, maxPrice: BN], options?: TransactionOptions) { - const [collectionId, nftId, price] = args - const $api = inst.getApi() - return $api.pipe( - map((api) => ({ - api, - submittable: api.tx.nftSales.buy(collectionId, nftId, ['Native', price.toString()]), - })), - switchMap(({ api, submittable }) => inst.wrapSignAndSend(api, submittable, options)) - ) - } - async function getAvailableCollectionId() { const $api = inst.getApi() @@ -436,12 +378,5 @@ export function getNftsModule(inst: Centrifuge) { createCollection, mintNft, transferNft, - sellNft, - removeNftListing, - buyNft, } } - -const parseHex = (value: string | number) => { - return new BN(value.toString().substring(2), 'hex').toString() -} diff --git a/centrifuge-js/src/modules/pools.ts b/centrifuge-js/src/modules/pools.ts index 3a49946796..b7b66f1435 100644 --- a/centrifuge-js/src/modules/pools.ts +++ b/centrifuge-js/src/modules/pools.ts @@ -131,8 +131,8 @@ export type LoanInfoInput = discountRate: BN maxBorrowAmount: 'upToTotalBorrowed' | 'upToOutstandingDebt' value: BN - maturityDate: Date - maturityExtensionDays: number + maturityDate: Date | null + maturityExtensionDays: number | null advanceRate: BN interestRate: BN } diff --git a/fabric/src/components/Banner/index.tsx b/fabric/src/components/Banner/index.tsx index 3ee4685430..38d0b3b600 100644 --- a/fabric/src/components/Banner/index.tsx +++ b/fabric/src/components/Banner/index.tsx @@ -14,7 +14,7 @@ type BannerProps = { children?: React.ReactNode } -export const Banner: React.FC = ({ children, title, ...props }) => { +export function Banner({ children, title, ...props }: BannerProps) { const theme = useTheme() const ref = React.useRef(null) const { overlayProps } = useOverlay({ ...props }, ref) diff --git a/fabric/src/components/Button/AnchorButton.tsx b/fabric/src/components/Button/AnchorButton.tsx index 376d3bd719..a544847536 100644 --- a/fabric/src/components/Button/AnchorButton.tsx +++ b/fabric/src/components/Button/AnchorButton.tsx @@ -14,7 +14,7 @@ const StyledAnchor = styled.a<{ $disabled?: boolean }>( (props) => props.$disabled && { pointerEvents: 'none' } ) -export const AnchorButton: React.FC = ({ +export function AnchorButton({ variant, small, icon, @@ -25,7 +25,7 @@ export const AnchorButton: React.FC = ({ children, active, ...anchorProps -}) => { +}: AnchorButtonProps) { return ( = ({ +export function Button({ variant, small, icon, @@ -28,7 +28,7 @@ export const Button: React.FC = ({ active, type = 'button', ...buttonProps -}) => { +}: ButtonProps) { return ( = ({ +export function WalletButton({ icon = 'polkadot', small = true, disabled, @@ -51,7 +51,7 @@ export const WalletButton: React.VFC = ({ alias, balance, ...buttonProps -}) => { +}: WalletButtonProps) { return ( & { extendedClickArea?: boolean } -export const Checkbox: React.VFC = ({ label, errorMessage, extendedClickArea, ...checkboxProps }) => { +export function Checkbox({ label, errorMessage, extendedClickArea, ...checkboxProps }: CheckboxProps) { return ( diff --git a/fabric/src/components/Dialog/Dialog.stories.tsx b/fabric/src/components/Dialog/Dialog.stories.tsx index 58f10bd01d..a0c091038a 100644 --- a/fabric/src/components/Dialog/Dialog.stories.tsx +++ b/fabric/src/components/Dialog/Dialog.stories.tsx @@ -9,7 +9,7 @@ export default { title: 'Components/Dialog', } -export const Default: React.FC = () => { +export function Default() { const [open, setOpen] = React.useState(false) return ( <> diff --git a/fabric/src/components/FabricProvider/index.tsx b/fabric/src/components/FabricProvider/index.tsx index 18fc16d25c..0446dc7df9 100644 --- a/fabric/src/components/FabricProvider/index.tsx +++ b/fabric/src/components/FabricProvider/index.tsx @@ -6,7 +6,7 @@ type Props = React.PropsWithChildren<{ theme: DefaultTheme }> -export const FabricProvider: React.FC = ({ theme, children }) => { +export function FabricProvider({ theme, children }: Props) { return ( {children} diff --git a/fabric/src/components/InlineFeedback/index.tsx b/fabric/src/components/InlineFeedback/index.tsx index 69f055949f..79cbf2a0ad 100644 --- a/fabric/src/components/InlineFeedback/index.tsx +++ b/fabric/src/components/InlineFeedback/index.tsx @@ -19,7 +19,7 @@ const icons = { critical: IconInfoFailed, } -export const InlineFeedback: React.FC = ({ status = 'default', children }) => { +export function InlineFeedback({ status = 'default', children }: InlineFeedbackProps) { return ( diff --git a/fabric/src/components/InteractiveCard/index.tsx b/fabric/src/components/InteractiveCard/index.tsx index b938a3688a..69c925ec1f 100644 --- a/fabric/src/components/InteractiveCard/index.tsx +++ b/fabric/src/components/InteractiveCard/index.tsx @@ -25,7 +25,7 @@ type OwnProps = { export type InteractiveCardProps = OwnProps & Omit -export const InteractiveCard: React.FC = (props) => { +export function InteractiveCard(props: InteractiveCardProps) { const { variant = 'default', icon, diff --git a/fabric/src/components/LayoutGrid/LayoutGrid.stories.tsx b/fabric/src/components/LayoutGrid/LayoutGrid.stories.tsx index de35d12c11..715327302e 100644 --- a/fabric/src/components/LayoutGrid/LayoutGrid.stories.tsx +++ b/fabric/src/components/LayoutGrid/LayoutGrid.stories.tsx @@ -6,7 +6,7 @@ export default { title: 'Components/LayoutGrid', } -export const Default: React.FC = () => { +export function Default() { return ( diff --git a/fabric/src/components/LayoutGrid/index.tsx b/fabric/src/components/LayoutGrid/index.tsx index bf124a7726..0349a82460 100644 --- a/fabric/src/components/LayoutGrid/index.tsx +++ b/fabric/src/components/LayoutGrid/index.tsx @@ -6,7 +6,7 @@ import { Grid, GridProps } from '../Grid' export type LayoutGridProps = Omit -export const LayoutGrid: React.FC = ({ children, ...rest }) => { +export function LayoutGrid({ children, ...rest }: LayoutGridProps) { return ( {children} @@ -19,7 +19,7 @@ type ItemProps = BoxProps & { push?: ResponsiveValue } -export const LayoutGridItem: React.FC = ({ span, push, children, ...rest }) => { +export function LayoutGridItem({ span, push, children, ...rest }: ItemProps) { return ( <> {push && ( diff --git a/fabric/src/components/Menu/index.tsx b/fabric/src/components/Menu/index.tsx index ca2ec7cb15..34c6812043 100644 --- a/fabric/src/components/Menu/index.tsx +++ b/fabric/src/components/Menu/index.tsx @@ -11,7 +11,7 @@ import { Text } from '../Text' export type MenuProps = Omit -export const Menu: React.FC = ({ children, ...cardProps }) => { +export function Menu({ children, ...cardProps }: MenuProps) { return ( {children} @@ -27,7 +27,7 @@ const ScrollContainer = styled(Stack)` } ` -export const MenuItemGroup: React.FC<{ children: React.ReactNode }> = ({ children }) => { +export function MenuItemGroup({ children }: { children: React.ReactNode }) { return ( <> @@ -55,14 +55,14 @@ export type MenuItemProps = { } & PropsOf & React.HTMLAttributes -export const MenuItem: React.FC = ({ +export function MenuItem({ label, sublabel, icon: IconComp, iconRight: IconRightComp, minHeight = '48px', ...buttonProps -}) => { +}: MenuItemProps) { return ( diff --git a/fabric/src/components/Pagination/Pagination.stories.tsx b/fabric/src/components/Pagination/Pagination.stories.tsx index 241c6992e3..6a006116f6 100644 --- a/fabric/src/components/Pagination/Pagination.stories.tsx +++ b/fabric/src/components/Pagination/Pagination.stories.tsx @@ -5,6 +5,6 @@ export default { title: 'Components/Pagination', } -export const Default: React.FC = () => { +export function Default() { return } diff --git a/fabric/src/components/Popover/index.tsx b/fabric/src/components/Popover/index.tsx index 5f6f819308..ea9c138a64 100644 --- a/fabric/src/components/Popover/index.tsx +++ b/fabric/src/components/Popover/index.tsx @@ -18,7 +18,7 @@ type PopoverProps = { placement?: AriaPositionProps['placement'] } -export const Popover: React.FC = ({ renderTrigger, renderContent, placement }) => { +export function Popover({ renderTrigger, renderContent, placement }: PopoverProps) { const state = useOverlayTriggerState({}) const overlayRef = React.useRef(null) const triggerRef = React.useRef(null) diff --git a/fabric/src/components/Positioner/index.tsx b/fabric/src/components/Positioner/index.tsx index bd71451de8..fb30c384a2 100644 --- a/fabric/src/components/Positioner/index.tsx +++ b/fabric/src/components/Positioner/index.tsx @@ -12,14 +12,14 @@ type PositionerProps = { render: (props: React.HTMLAttributes & { pointer: PlacementAxis }) => React.ReactElement } -const PositionerInner: React.FC = ({ +function PositionerInner({ isShown, targetRef, overlayRef, placement = 'bottom', offset = 1, render, -}) => { +}: PositionerProps) { const theme = useTheme() const { overlayProps, ...restProps } = useOverlayPosition({ targetRef, @@ -32,7 +32,7 @@ const PositionerInner: React.FC = ({ return render({ ...overlayProps, pointer: restProps.placement }) } -export const Positioner: React.FC = (props) => { +export function Positioner(props: PositionerProps) { return props.isShown ? ( diff --git a/fabric/src/components/RadioButton/index.tsx b/fabric/src/components/RadioButton/index.tsx index b4c14f5f73..d9f016b3b3 100644 --- a/fabric/src/components/RadioButton/index.tsx +++ b/fabric/src/components/RadioButton/index.tsx @@ -11,7 +11,7 @@ export type RadioButtonProps = React.InputHTMLAttributes & { textStyle?: string } -export const RadioButton: React.VFC = ({ label, errorMessage, textStyle, ...radioProps }) => { +export function RadioButton({ label, errorMessage, textStyle, ...radioProps }: RadioButtonProps) { return (