Skip to content

Commit

Permalink
Edit pool fields (#2455)
Browse files Browse the repository at this point in the history
* Fix report url and clean up pre edit view

* Add pool structure, fix pool name in tranche edit, fix targetAPY,
  • Loading branch information
sophialittlejohn authored Sep 18, 2024
1 parent 4806f75 commit 70aa42c
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 149 deletions.
173 changes: 94 additions & 79 deletions centrifuge-app/src/components/IssuerSection.tsx
Original file line number Diff line number Diff line change
@@ -1,85 +1,61 @@
import { PoolMetadata } from '@centrifuge/centrifuge-js'
import { useCentrifuge } from '@centrifuge/centrifuge-react'
import { Accordion, AnchorButton, Box, IconExternalLink, Shelf, Text } from '@centrifuge/fabric'
import { Accordion, AnchorButton, Box, IconExternalLink, Shelf, Stack, Text } from '@centrifuge/fabric'
import * as React from 'react'
import { useLocation } from 'react-router'
import { ExecutiveSummaryDialog } from './Dialogs/ExecutiveSummaryDialog'
import { LabelValueStack } from './LabelValueStack'
import { PillButton } from './PillButton'
import { AnchorTextLink, RouterTextLink } from './TextLink'
import { AnchorTextLink } from './TextLink'

type IssuerSectionProps = {
metadata: Partial<PoolMetadata> | undefined
}

const reportLinks = [
{ label: 'Balance sheet', href: '/balance-sheet' },
{ label: 'Profit & loss', href: '/profit-and-loss' },
{ label: 'Cashflow statement', href: '/cash-flow-statement' },
{ label: 'View all', href: '/' },
]

export function ReportDetails({ metadata }: IssuerSectionProps) {
const cent = useCentrifuge()
const { pathname } = useLocation()
const report = metadata?.pool?.reports?.[0]

return (
<Shelf flexDirection="column" alignItems="flex-start">
<Shelf marginBottom={30}>
<LabelValueStack
label=""
value={
<Text variant="body1">
<Shelf flexWrap="wrap" gap={2} alignItems="flex-start">
{reportLinks.map((link, i) => (
<RouterTextLink to={`${pathname}/reporting${link.href}`} key={`${link.label}-${i}`}>
{link.label}
</RouterTextLink>
))}
</Shelf>
</Text>
}
/>
<Stack gap={2}>
<Text variant="heading2">Pool analysis</Text>
<Shelf flexDirection="column" alignItems="flex-start">
{report && (
<>
<Shelf gap={1}>
{report.author.avatar?.uri && (
<Box
as="img"
height={40}
borderRadius={30}
src={cent.metadata.parseMetadataUrl(report.author.avatar.uri)}
alt=""
/>
)}
{report.author.name && (
<LabelValueStack label="Reviewer" value={<Text variant="body2">{report.author.name}</Text>} />
)}
{report.author.title && (
<LabelValueStack label="Reviewer title" value={<Text variant="body2">{report.author.title}</Text>} />
)}
</Shelf>
<Shelf marginTop={20}>
<AnchorButton href={report.uri} target="_blank" variant="secondary" icon={IconExternalLink}>
View full analysis
</AnchorButton>
</Shelf>
</>
)}
</Shelf>
{report && (
<>
<Text style={{ marginBottom: 8 }} variant="heading2">
Pool analysis
</Text>
<Shelf gap={1}>
{report.author.avatar?.uri && (
<Box
as="img"
height={40}
borderRadius={30}
src={cent.metadata.parseMetadataUrl(report.author.avatar.uri)}
alt=""
/>
)}
<Text variant="body2">
Reviewer: {report.author.name}
<br />
{report.author.title}
</Text>
</Shelf>
<Shelf marginTop={20}>
<AnchorButton href={report.uri} target="_blank" variant="secondary" icon={IconExternalLink}>
View full report
</AnchorButton>
</Shelf>
</>
)}
</Shelf>
</Stack>
)
}

export function IssuerDetails({ metadata }: IssuerSectionProps) {
const cent = useCentrifuge()
const [isDialogOpen, setIsDialogOpen] = React.useState(false)
return (
<>
<Shelf gap={1}>
<Stack gap={2}>
<Stack gap={1}>
{metadata?.pool?.issuer.logo && (
<Box
as="img"
Expand All @@ -89,28 +65,38 @@ export function IssuerDetails({ metadata }: IssuerSectionProps) {
src={cent.metadata.parseMetadataUrl(metadata?.pool?.issuer.logo?.uri)}
/>
)}
<Text variant="body2">{metadata?.pool?.issuer.name}</Text>
</Shelf>
<Text variant="body2">{metadata?.pool?.issuer.description}</Text>

{metadata?.pool?.links.executiveSummary && (
<LabelValueStack label="Issuer" value={<Text variant="body2">{metadata?.pool?.issuer.name}</Text>} />
<LabelValueStack
label="Download"
value={
<>
<PillButton variant="small" onClick={() => setIsDialogOpen(true)}>
Executive summary
</PillButton>
<ExecutiveSummaryDialog
issuerName={metadata?.pool?.issuer.name}
href={cent.metadata.parseMetadataUrl(metadata?.pool?.links.executiveSummary?.uri)}
open={isDialogOpen}
onClose={() => setIsDialogOpen(false)}
/>
</>
}
label="Legal representative"
value={<Text variant="body2">{metadata?.pool?.issuer.repName}</Text>}
/>
)}
<LabelValueStack
label="Short description"
value={<Text variant="body2">{metadata?.pool?.issuer.shortDescription}</Text>}
/>
<LabelValueStack
label="Description"
value={<Text variant="body2">{metadata?.pool?.issuer.description}</Text>}
/>
{metadata?.pool?.links.executiveSummary && (
<LabelValueStack
label="Download"
value={
<>
<PillButton variant="small" onClick={() => setIsDialogOpen(true)}>
Executive summary
</PillButton>
<ExecutiveSummaryDialog
issuerName={metadata?.pool?.issuer.name}
href={cent.metadata.parseMetadataUrl(metadata?.pool?.links.executiveSummary?.uri)}
open={isDialogOpen}
onClose={() => setIsDialogOpen(false)}
/>
</>
}
/>
)}
</Stack>

{(metadata?.pool?.links.website || metadata?.pool?.links.forum || metadata?.pool?.issuer.email) && (
<LabelValueStack
Expand All @@ -135,6 +121,35 @@ export function IssuerDetails({ metadata }: IssuerSectionProps) {
{!!metadata?.pool?.details?.length && (
<LabelValueStack label="Details" value={<Accordion items={metadata?.pool?.details} />} />
)}
</>
</Stack>
)
}

export function RatingDetails({ metadata }: IssuerSectionProps) {
const rating = metadata?.pool?.rating

return (
<Stack gap={1}>
<Text variant="heading2">Pool rating</Text>
<Shelf flexDirection="column" alignItems="flex-start">
{rating && (
<Shelf gap={1}>
{rating.ratingAgency && (
<LabelValueStack label="Rating agency" value={<Text variant="body2">{rating.ratingAgency}</Text>} />
)}
{rating.ratingValue && (
<LabelValueStack label="Rating" value={<Text variant="body2">{rating.ratingValue}</Text>} />
)}
</Shelf>
)}
</Shelf>
<Shelf>
{rating?.ratingReportUrl && (
<AnchorButton href={rating.ratingReportUrl} target="_blank" variant="secondary" icon={IconExternalLink}>
View full report
</AnchorButton>
)}
</Shelf>
</Stack>
)
}
20 changes: 20 additions & 0 deletions centrifuge-app/src/pages/IssuerCreatePool/PoolRatingInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Grid, Stack, Text, TextInput } from '@centrifuge/fabric'
import { FieldWithErrorMessage } from '../../components/FieldWithErrorMessage'

export function PoolRatingInput() {
return (
<Stack gap={2}>
<Text variant="heading2">Pool rating</Text>
<Grid columns={[1, 2]} equalColumns gap={2} rowGap={3}>
<FieldWithErrorMessage name="ratingAgency" as={TextInput} label="Rating agency" placeholder="Agency Name..." />
<FieldWithErrorMessage name="ratingValue" as={TextInput} label="Rating" placeholder="Rating value..." />
<FieldWithErrorMessage
name="ratingReportUrl"
as={TextInput}
label="Rating report URL"
placeholder="https://..."
/>
</Grid>
</Stack>
)
}
88 changes: 44 additions & 44 deletions centrifuge-app/src/pages/IssuerCreatePool/PoolReportsInput.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,53 @@
import { FileUpload, Grid, TextInput } from '@centrifuge/fabric'
import { FileUpload, Grid, Stack, Text, TextInput } from '@centrifuge/fabric'
import { Field, FieldProps } from 'formik'
import { FieldWithErrorMessage } from '../../components/FieldWithErrorMessage'
import { combineAsync, imageFile, maxFileSize, maxImageSize } from '../../utils/validation'
import { validate } from './validate'

export function PoolReportsInput() {
return (
<Grid columns={[1, 2]} equalColumns gap={2} rowGap={3}>
<FieldWithErrorMessage
name="reportUrl"
as={TextInput}
label="Report URL"
placeholder="https://..."
validate={validate.websiteNotRequired}
/>
<FieldWithErrorMessage
name="reportAuthorName"
as={TextInput}
label="Reviewer name"
placeholder="Name..."
maxLength={100}
/>
<FieldWithErrorMessage
name="reportAuthorTitle"
as={TextInput}
label="Reviewer job title"
placeholder="Title..."
maxLength={100}
/>
<Field
name="reportAuthorAvatar"
validate={combineAsync(imageFile(), maxFileSize(1024 ** 2), maxImageSize(200, 200))}
>
{({ field, meta, form }: FieldProps) => (
<FileUpload
file={field.value}
onFileChange={(file) => {
form.setFieldTouched('reportAuthorAvatar', true, false)
form.setFieldValue('reportAuthorAvatar', file)
}}
label="Reviewer avatar (JPG/PNG/SVG, max 40x40px)"
errorMessage={meta.touched && meta.error ? meta.error : undefined}
accept="image/*"
/>
)}
</Field>
<FieldWithErrorMessage name="ratingAgency" as={TextInput} label="Rating agency" placeholder="Agency Name..." />
<FieldWithErrorMessage name="ratingValue" as={TextInput} label="Rating" placeholder="Rating value..." />
<FieldWithErrorMessage name="ratingReport" as={TextInput} label="Rating report URL" placeholder="https://..." />
</Grid>
<Stack gap={2}>
<Text variant="heading2">Pool analysis</Text>
<Grid columns={[1, 2]} equalColumns gap={2} rowGap={3}>
<FieldWithErrorMessage
name="reportUrl"
as={TextInput}
label="Report URL"
placeholder="https://..."
validate={validate.websiteNotRequired}
/>
<FieldWithErrorMessage
name="reportAuthorName"
as={TextInput}
label="Reviewer name"
placeholder="Name..."
maxLength={100}
/>
<FieldWithErrorMessage
name="reportAuthorTitle"
as={TextInput}
label="Reviewer job title"
placeholder="Title..."
maxLength={100}
/>
<Field
name="reportAuthorAvatar"
validate={combineAsync(imageFile(), maxFileSize(1024 ** 2), maxImageSize(200, 200))}
>
{({ field, meta, form }: FieldProps) => (
<FileUpload
file={field.value}
onFileChange={(file) => {
form.setFieldTouched('reportAuthorAvatar', true, false)
form.setFieldValue('reportAuthorAvatar', file)
}}
label="Reviewer avatar (JPG/PNG/SVG, max 40x40px)"
errorMessage={meta.touched && meta.error ? meta.error : undefined}
accept="image/*"
/>
)}
</Field>
</Grid>
</Stack>
)
}
20 changes: 14 additions & 6 deletions centrifuge-app/src/pages/IssuerCreatePool/TrancheInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,28 +67,36 @@ export function TrancheSection() {
</Button>
}
>
<TrancheInput canRemove />
<TrancheInput canRemove poolName={values.poolName} />
</PageSection>
)}
</FieldArray>
)
}

export function TrancheInput({ canRemove, isUpdating }: { canRemove?: boolean; isUpdating?: boolean }) {
export function TrancheInput({
canRemove,
isUpdating,
poolName,
}: {
canRemove?: boolean
isUpdating?: boolean
poolName?: string
}) {
const fmk = useFormikContext<PoolMetadataInput>()
const { values } = fmk

const getTrancheName = (index: number) => {
if (values.tranches.length === 1) {
return values.poolName
return poolName
}
switch (index) {
case 0:
return `${values.poolName} Junior`
return `${poolName} Junior`
case 1:
return values.tranches.length === 2 ? `${values.poolName} Senior` : `${values.poolName} Mezzanine`
return values.tranches.length === 2 ? `${poolName} Senior` : `${poolName} Mezzanine`
case 2:
return `${values.poolName} Senior`
return `${poolName} Senior`
default:
return ''
}
Expand Down
Loading

0 comments on commit 70aa42c

Please sign in to comment.