Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Design feedback #2504

Merged
merged 5 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions centrifuge-app/src/components/IssuerSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,13 @@ export function IssuerDetails({ metadata }: IssuerSectionProps) {
</Text>
</Box>
{metadata?.pool?.issuer?.categories?.length ? (
<Box width="50%" bg="white" padding={2} borderRadius={10} ml={1} height="min-content">
<Box width="50%" bg="white" padding={2} borderRadius={10} ml={1} height="min-content" alignSelf="center">
{metadata?.pool?.issuer?.categories.map((category) => (
<Box display="flex" justifyContent="space-between" padding={1}>
<Text color="textSecondary" variant="body2" style={{ minWidth: 120, textTransform: 'capitalize' }}>
<Text color="textSecondary" variant="body3" style={{ minWidth: 120, textTransform: 'capitalize' }}>
{formatCamelCase(category.customType) || formatCamelCase(category.type)}
</Text>
<Text variant="body2" style={{ fontWeight: 500 }}>
<Text variant="body3" style={{ fontWeight: 500 }}>
{category.type.includes('Rate') ? formatPercentage(category.value) : category.value}
</Text>
</Box>
Expand Down
48 changes: 31 additions & 17 deletions centrifuge-app/src/components/PoolCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@
const StyledCard = styled(Card)`
width: 100%;
max-width: 100%;
height: 300px;

height: 320px;
margin-right: 12px;
margin-bottom: 12px;
padding: 12px;
Expand Down Expand Up @@ -72,7 +71,8 @@
{ name: 'Senior', apr: '7%', minInvestment: '5K' },
],
shortDescription: ' Real estate bridge loans for fix and flip projects, maturing in 12-24 months.',
investorType: 'Qualified Investors',
investorType: 'Qualified US and non-US investors',
assetType: 'Residential real estate',
},
BT3: {
name: 'BlockTower Series 3',
Expand All @@ -82,6 +82,7 @@
],
shortDescription: ' Investment-grade consumer ABS, auto ABS, and CLOs under 4 years.',
investorType: 'Private',
assetType: 'Structured Credit',
},
BT4: {
name: 'BlockTower Series 4',
Expand All @@ -91,6 +92,7 @@
],
shortDescription: 'Investment-grade consumer ABS, auto ABS, and CLOs under 4 years.',
investorType: 'Private',
assetType: 'Structured Credit',
},
none: {
name: '-',
Expand All @@ -100,16 +102,18 @@
],
shortDescription: '',
investorType: '-',
assetType: '-',
},
}

export const DYF_POOL_ID = '1655476167'
export const NS3_POOL_ID = '1615768079'
export const NS2 = '0x53b2d22d07E069a3b132BfeaaD275b10273d381E'

export type CentrifugeTargetAPYs = keyof typeof centrifugeTargetAPYs
export const centrifugeTargetAPYs = {
[DYF_POOL_ID]: ['15%'],
[NS3_POOL_ID]: ['8.0%', '16%'],
[NS3_POOL_ID]: ['16%', '8%'],
}

type TinlakeTranchesKey = keyof typeof tinlakeTranches
Expand Down Expand Up @@ -148,19 +152,26 @@
(key) => tinlakeTranches[key as TinlakeTranchesKey].name === name
) || 'none') as TinlakeTranchesKey

const renderText = (text: string, isApr?: boolean) => {
if (isApr && poolId === NS3_POOL_ID) {
const renderText = (text: string, isApr?: boolean, seniority?: number) => {
if (
(isApr && poolId === NS3_POOL_ID) ||
(isApr && poolId === DYF_POOL_ID) ||
(isApr && isTinlakePool && seniority === 0)
) {
return (
<Box display="flex">
<Box display="flex" alignItems="baseline">
<Text
fontWeight={500}
as="h2"
variant={isOneTranche ? 'heading1' : 'body1'}
style={{ width: 35, marginRight: 4 }}
style={{
width: isOneTranche ? 40 : 35,
marginRight: isOneTranche ? 12 : 4,
}}
>
{text}
</Text>
<Tooltips type="targetAPY" color="textSecondary" label="Target" size="xs" />
<Tooltips type="targetAPY" color="textSecondary" label="target" size="xs" />
</Box>
)
}
Expand All @@ -171,7 +182,7 @@
)
}

const calculateApy = (tranche: TrancheWithCurrency) => {

Check warning on line 185 in centrifuge-app/src/components/PoolCard/index.tsx

View workflow job for this annotation

GitHub Actions / build-app

The 'calculateApy' function makes the dependencies of useMemo Hook (at line 223) change on every render. Move it inside the useMemo callback. Alternatively, wrap the definition of 'calculateApy' in its own useCallback() Hook

Check warning on line 185 in centrifuge-app/src/components/PoolCard/index.tsx

View workflow job for this annotation

GitHub Actions / ff-prod / build-app

The 'calculateApy' function makes the dependencies of useMemo Hook (at line 223) change on every render. Move it inside the useMemo callback. Alternatively, wrap the definition of 'calculateApy' in its own useCallback() Hook
const daysSinceCreation = createdAt ? daysBetween(createdAt, new Date()) : 0
if (poolId === DYF_POOL_ID) return centrifugeTargetAPYs[DYF_POOL_ID][0]
if (poolId === NS3_POOL_ID && tranche.seniority === 0) return centrifugeTargetAPYs[NS3_POOL_ID][0]
Expand All @@ -196,6 +207,7 @@
).toDecimal()

return {
seniority: tranche.seniority,
name: trancheName,
apr: isTinlakePool
? tinlakeTranches[tinlakeKey].tranches.find((t) => t.name === trancheName)?.apr
Expand Down Expand Up @@ -263,32 +275,34 @@
)}
<Stack>
<Text as="span" variant="body3" color="textButtonPrimaryDisabled">
{poolId === DYF_POOL_ID ? 'Target' : 'APY'}
APY
</Text>
{tranchesData?.map((tranche) => renderText(`${tranche.apr}`, true))}
{tranchesData?.map((tranche) => renderText(`${tranche.apr}`, true, tranche.seniority))}
</Stack>
<Stack>
<Text as="span" variant="body3" color="textButtonPrimaryDisabled">
<Text as="span" variant="body2" color="textButtonPrimaryDisabled">
Min. investment
</Text>
{tranchesData?.map((tranche) => renderText(`${tranche.minInvestment}`))}
</Stack>
</Box>
{(metaData?.pool?.issuer?.shortDescription || isTinlakePool) && (
<Box marginY={12}>
<Text as="p" variant="body3" color="textButtonPrimaryDisabled">
<Text as="p" variant="body2" color="textButtonPrimaryDisabled">
{isTinlakePool ? tinlakeTranches[tinlakeKey].shortDescription : metaData?.pool?.issuer?.shortDescription}
</Text>
</Box>
)}

<Box display="flex" justifyContent="space-between" mt={1}>
<Text variant="body3">Asset type</Text>
<StyledText variant="body3">{assetClass ?? '-'}</StyledText>
<Text variant="body2">Asset type</Text>
<StyledText variant="body2">
{isTinlakePool ? tinlakeTranches[tinlakeKey].assetType : assetClass ?? '-'}
</StyledText>
</Box>
<Box display="flex" justifyContent="space-between">
<Text variant="body3">Investor type</Text>
<StyledText variant="body3">
<Text variant="body2">Investor type</Text>
<StyledText variant="body2">
{isTinlakePool ? tinlakeTranches[tinlakeKey].investorType : metaData?.pool?.investorType ?? '-'}
</StyledText>
</Box>
Expand Down
6 changes: 3 additions & 3 deletions centrifuge-app/src/components/PoolList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
const [listedPools, , metadataIsLoading] = useListedPools()
const isLarge = useIsAboveBreakpoint('L')
const isMedium = useIsAboveBreakpoint('M')
const isExtraLarge = useIsAboveBreakpoint('XL')

Check warning on line 47 in centrifuge-app/src/components/PoolList.tsx

View workflow job for this annotation

GitHub Actions / build-app

'isExtraLarge' is assigned a value but never used

Check warning on line 47 in centrifuge-app/src/components/PoolList.tsx

View workflow job for this annotation

GitHub Actions / ff-prod / build-app

'isExtraLarge' is assigned a value but never used

const centPools = listedPools.filter(({ id }) => !id.startsWith('0x')) as Pool[]
const centPoolsMetaData: PoolMetaDataPartial[] = useMetadataMulti<PoolMetadata>(
Expand Down Expand Up @@ -87,7 +87,7 @@
? Array(6)
.fill(true)
.map((_, index) => (
<Box as="li" key={index} width={isExtraLarge ? '25%' : isLarge ? '33%' : isMedium ? '48%' : '100%'}>
<Box as="li" key={index} width={isLarge ? '33%' : isMedium ? '48%' : '100%'}>
<PoolCard />
</Box>
))
Expand All @@ -96,7 +96,7 @@
as="li"
key={pool.poolId}
status={pool.status}
width={isExtraLarge ? '25%' : isLarge ? '33%' : isMedium ? '48%' : '100%'}
width={isLarge ? '33%' : isMedium ? '48%' : '100%'}
>
<PoolCard {...pool} />
</PoolCardBox>
Expand Down Expand Up @@ -127,7 +127,7 @@
function ArchivedPools({ pools }: { pools: PoolCardProps[] }) {
const isMedium = useIsAboveBreakpoint('M')
const isLarge = useIsAboveBreakpoint('L')
const isExtraLarge = useIsAboveBreakpoint('XL')

Check warning on line 130 in centrifuge-app/src/components/PoolList.tsx

View workflow job for this annotation

GitHub Actions / build-app

'isExtraLarge' is assigned a value but never used

Check warning on line 130 in centrifuge-app/src/components/PoolList.tsx

View workflow job for this annotation

GitHub Actions / ff-prod / build-app

'isExtraLarge' is assigned a value but never used
return (
<Stack gap={1} overflow="auto">
<Box as="ul" role="list" display="flex" flexWrap="wrap">
Expand All @@ -136,7 +136,7 @@
as="li"
key={pool.poolId}
status={pool.status}
width={isExtraLarge ? '25%' : isLarge ? '33%' : isMedium ? '48%' : '100%'}
width={isLarge ? '33%' : isMedium ? '48%' : '100%'}
>
<PoolCard {...pool} />
</PoolCardBox>
Expand Down
32 changes: 25 additions & 7 deletions centrifuge-app/src/components/PoolOverview/KeyMetrics.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { CurrencyBalance, DailyTrancheState, Price } from '@centrifuge/centrifuge-js'
import { NetworkIcon, formatBalanceAbbreviated, useCentrifuge } from '@centrifuge/centrifuge-react'
import { Box, Card, IconArrowRightWhite, IconMoody, IconSp, Shelf, Stack, Text, Tooltip } from '@centrifuge/fabric'
import {
Box,
Card,
IconArrowRightWhite,
IconMoody,
IconParticula,
IconSp,
Shelf,
Stack,
Text,
Tooltip,
} from '@centrifuge/fabric'
import capitalize from 'lodash/capitalize'
import startCase from 'lodash/startCase'
import { useMemo } from 'react'
Expand Down Expand Up @@ -35,6 +46,11 @@ type Tranche = Pick<DailyTrancheState, 'id'> & {

type TinlakeDataKey = keyof typeof tinlakeData

const ratingIcons: { [key: string]: JSX.Element } = {
"Moody's": <IconMoody size={16} />,
Particula: <IconParticula size={16} />,
}

const tinlakeData = {
'0x53b2d22d07E069a3b132BfeaaD275b10273d381E': '7% - 15%',
'0x55d86d51Ac3bcAB7ab7d2124931FbA106c8b60c7': '4% - 15%',
Expand Down Expand Up @@ -124,7 +140,7 @@ export const KeyMetrics = ({ poolId }: Props) => {
value: tinlakeData[poolId as TinlakeDataKey]
? tinlakeData[poolId as TinlakeDataKey]
: centrifugeTargetAPYs[poolId as keyof typeof centrifugeTargetAPYs]
? centrifugeTargetAPYs[poolId as keyof typeof centrifugeTargetAPYs].join(' - ')
? centrifugeTargetAPYs[poolId as keyof typeof centrifugeTargetAPYs].reverse().join(' - ')
: tranchesAPY?.length
? tranchesAPY.map((tranche, index) => {
const formatted = formatPercentage(tranche)
Expand Down Expand Up @@ -176,17 +192,16 @@ export const KeyMetrics = ({ poolId }: Props) => {
<Shelf gap={1}>
{metadata?.pool?.poolRatings.map((rating) => (
<Tooltip
delay={300}
bodyWidth="maxContent"
body={
<TooltipBody
title={rating.agency ?? ''}
links={[
{ text: 'View report', url: rating.reportUrl ?? '' },
{ text: 'Go to report', url: rating.reportUrl ?? '' },
...(rating.reportFile
? [
{
text: 'Download report',
text: 'View PDF report',
url: cent.metadata.parseMetadataUrl(rating.reportFile?.uri ?? ''),
},
]
Expand All @@ -200,9 +215,12 @@ export const KeyMetrics = ({ poolId }: Props) => {
borderRadius={20}
padding="2px 10px"
display="flex"
alignItems="center"
width={80}
justifyContent="center"
>
{rating.agency?.includes('moody') ? <IconMoody size={16} /> : <IconSp size={16} />}
<Text>{rating.value}</Text>
{rating.agency && ratingIcons[rating.agency] ? ratingIcons[rating.agency] : <IconSp size={16} />}
<Text style={{ marginLeft: 4 }}>{rating.value}</Text>
</Box>
</Tooltip>
))}
Expand Down
25 changes: 16 additions & 9 deletions centrifuge-app/src/components/PoolOverview/TrancheTokenCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { DataTable } from '../DataTable'
import { CentrifugeTargetAPYs, DYF_POOL_ID, NS3_POOL_ID, centrifugeTargetAPYs } from '../PoolCard'
import { PoolMetaDataPartial } from '../PoolList'
import { Tooltips } from '../Tooltips'

type Row = {
tokenName: string
Expand All @@ -18,10 +19,9 @@
tokenPrice: Decimal
subordination: Decimal
trancheId: string
isTarget: boolean
}

const NS2 = '0x53b2d22d07E069a3b132BfeaaD275b10273d381E'

export const TrancheTokenCards = ({
trancheTokens,
poolId,
Expand All @@ -34,6 +34,7 @@
const pool = usePool(poolId)
const theme = useTheme()
const isTinlakePool = poolId.startsWith('0x')
const daysSinceCreation = pool?.createdAt ? daysBetween(new Date(pool.createdAt), new Date()) : 0

const getTrancheText = (trancheToken: Token) => {
if (trancheToken.seniority === 0) return 'junior'
Expand All @@ -43,19 +44,21 @@

const calculateApy = (trancheToken: Token) => {
if (isTinlakePool && getTrancheText(trancheToken) === 'senior') return formatPercentage(trancheToken.apy)
if (poolId === NS2 && trancheToken.seniority === 0) return '15%'
if (isTinlakePool && trancheToken.seniority === 0) return '15%'
if (poolId === DYF_POOL_ID) return centrifugeTargetAPYs[poolId as CentrifugeTargetAPYs][0]
if (poolId === NS3_POOL_ID && trancheToken.seniority === 0)
return centrifugeTargetAPYs[poolId as CentrifugeTargetAPYs][0]
if (poolId === NS3_POOL_ID && trancheToken.seniority === 1)
return centrifugeTargetAPYs[poolId as CentrifugeTargetAPYs][1]
const daysSinceCreation = pool?.createdAt ? daysBetween(new Date(pool.createdAt), new Date()) : 0
if (daysSinceCreation < 30) return 'N/A'
return trancheToken.yield30DaysAnnualized
? formatPercentage(new Perquintill(trancheToken.yield30DaysAnnualized))
: '-'
}

const getTarget = (tranche: Token) =>
(isTinlakePool && tranche.seniority === 0) || poolId === DYF_POOL_ID || poolId === NS3_POOL_ID

const columns = useMemo(() => {
return [
{
Expand All @@ -71,13 +74,16 @@
},
},
{
header: poolId === DYF_POOL_ID || poolId === NS3_POOL_ID ? 'Target' : 'APY',
header: 'APY',
align: 'left',
cell: (row: Row) => {
return (
<Text paddingY={2} fontWeight="600" variant="heading2">
{row.apy}
</Text>
<Box>
<Text style={{ marginRight: 4 }} fontWeight="600" variant="heading2">
{row.apy}
</Text>
{row.isTarget && <Tooltips label="target" type="targetAPY" size="xs" />}
</Box>
)
},
},
Expand Down Expand Up @@ -126,7 +132,7 @@
},
},
]
}, [pool.tranches, metadata, poolId])

Check warning on line 135 in centrifuge-app/src/components/PoolOverview/TrancheTokenCards.tsx

View workflow job for this annotation

GitHub Actions / build-app

React Hook useMemo has a missing dependency: 'pool?.currency.symbol'. Either include it or remove the dependency array

Check warning on line 135 in centrifuge-app/src/components/PoolOverview/TrancheTokenCards.tsx

View workflow job for this annotation

GitHub Actions / ff-prod / build-app

React Hook useMemo has a missing dependency: 'pool?.currency.symbol'. Either include it or remove the dependency array

const dataTable = useMemo(() => {
return trancheTokens.map((tranche) => {
Expand All @@ -137,9 +143,10 @@
tokenPrice: tranche.tokenPrice,
subordination: tranche.protection,
trancheId: tranche.id,
isTarget: getTarget(tranche),
}
})
}, [trancheTokens])
}, [trancheTokens, getTarget])

Check warning on line 149 in centrifuge-app/src/components/PoolOverview/TrancheTokenCards.tsx

View workflow job for this annotation

GitHub Actions / build-app

React Hook useMemo has a missing dependency: 'calculateApy'. Either include it or remove the dependency array

Check warning on line 149 in centrifuge-app/src/components/PoolOverview/TrancheTokenCards.tsx

View workflow job for this annotation

GitHub Actions / ff-prod / build-app

React Hook useMemo has a missing dependency: 'calculateApy'. Either include it or remove the dependency array

return (
<Shelf gap={3}>
Expand Down
12 changes: 7 additions & 5 deletions centrifuge-app/src/pages/Pool/Overview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,16 @@ export function InvestButton(props: InvestRedeemProps) {
const connectAndOpen = useConnectBeforeAction(() => setOpen(true))
const { connectedType, showNetworks } = useWallet()
const navigate = useNavigate()
const isTinlakePool = poolId.startsWith('0x')

const getButtonText = (state: any) => {
if (!state.isAllowedToInvest && connectedType !== null) {
if (!state.isAllowedToInvest && connectedType !== null && !isTinlakePool) {
return 'Onboard'
} else if (connectedType === null) {
} else if (connectedType === null && !isTinlakePool) {
return 'Connect'
} else {
return state.isFirstInvestment ? 'Invest' : 'Invest/Redeem'
}
} else if (isTinlakePool) {
return 'Closed'
} else return state.isFirstInvestment ? 'Invest' : 'Invest/Redeem'
}

return (
Expand Down Expand Up @@ -193,6 +194,7 @@ export function InvestButton(props: InvestRedeemProps) {
}}
variant="primary"
loading={isLoading}
disabled={isTinlakePool}
>
{buttonText}
</Button>
Expand Down
Loading
Loading