Skip to content

Commit

Permalink
Onboarding: Issuer settings (restricted countries, upload subdocs) (#…
Browse files Browse the repository at this point in the history
…1422)

* Update UI for subdocs uploading

* Fix uploading for multitranches

* Add UI to restrict countries for KYB

* Add input to restrict KYC

* Fix naming

* Block onboarding on server for unspported countries

* Add message on frontend if country is unsupported

* Fix small bugs

* Rename component

* Add UI for blocking US investors

* Add mime type to agreements

* Add external onboarding link option
  • Loading branch information
sophialittlejohn authored May 30, 2023
1 parent e3d9561 commit 6542786
Show file tree
Hide file tree
Showing 13 changed files with 633 additions and 295 deletions.
2 changes: 2 additions & 0 deletions centrifuge-app/src/components/InvestRedeem/InvestRedeem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ const OnboardingButton = ({ networks }: { networks: Network[] | undefined }) =>
showWallets(networks?.length === 1 ? networks[0] : undefined)
} else if (investStatus === 'request') {
window.open(`mailto:${metadata?.pool?.issuer.email}?subject=New%20Investment%20Inquiry`)
} else if (metadata?.onboarding?.externalOnboardingUrl) {
window.open(metadata.onboarding.externalOnboardingUrl)
} else {
history.push(`/onboarding?poolId=${state.poolId}&trancheId=${state.trancheId}`)
}
Expand Down
122 changes: 0 additions & 122 deletions centrifuge-app/src/pages/IssuerPool/Configuration/OnboardingConfig.tsx

This file was deleted.

2 changes: 0 additions & 2 deletions centrifuge-app/src/pages/IssuerPool/Configuration/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { Details } from './Details'
import { EpochAndTranches } from './EpochAndTranches'
import { Issuer } from './Issuer'
import { LoanTemplates } from './LoanTemplates'
import { OnboardingConfig } from './OnboardingConfig'
import { PoolConfig } from './PoolConfig'
import { WriteOffGroups } from './WriteOffGroups'

Expand Down Expand Up @@ -41,7 +40,6 @@ const IssuerPoolConfiguration: React.FC = () => {
<WriteOffGroups />
<Admins />
<LoanTemplates />
<OnboardingConfig />
{editPoolConfig && <PoolConfig poolId={poolId} />}
</>
)}
Expand Down
159 changes: 159 additions & 0 deletions centrifuge-app/src/pages/IssuerPool/Investors/InvestorStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { findBalance, Pool, Token } from '@centrifuge/centrifuge-js'
import { useBalances, useCentrifugeTransaction } from '@centrifuge/centrifuge-react'
import {
Button,
Grid,
IconAlertCircle,
IconCheckCircle,
IconInfoFailed,
IconMinus,
IconPlus,
SearchInput,
Shelf,
Stack,
Text,
TextWithPlaceholder,
} from '@centrifuge/fabric'
import { isAddress } from '@polkadot/util-crypto'
import React from 'react'
import { useParams } from 'react-router'
import { DataTable } from '../../../components/DataTable'
import { PageSection } from '../../../components/PageSection'
import { usePermissions } from '../../../utils/usePermissions'
import { useOrder, usePool } from '../../../utils/usePools'

const SevenDaysMs = (7 * 24 + 1) * 60 * 60 * 1000 // 1 hour margin

export const InvestorStatus: React.FC = () => {
const { pid: poolId } = useParams<{ pid: string }>()
const [address, setAddress] = React.useState('')
const validAddress = isAddress(address) ? address : undefined
const permissions = usePermissions(validAddress)
const [pendingTrancheId, setPendingTrancheId] = React.useState('')

const { execute, isLoading: isTransactionPending } = useCentrifugeTransaction(
'Update investor',
(cent) => cent.pools.updatePoolRoles,
{}
)

const allowedTranches = Object.entries(permissions?.pools[poolId]?.tranches ?? {})
.filter(([, till]) => new Date(till).getTime() - Date.now() > SevenDaysMs)
.map(([tid]) => tid)

const pool = usePool(poolId) as Pool

function toggleAllowed(trancheId: string) {
if (!validAddress) return
const isAllowed = allowedTranches.includes(trancheId)
const OneHundredYearsFromNow = Math.floor(Date.now() / 1000 + 10 * 365 * 24 * 60 * 60)
const SevenDaysFromNow = Math.floor((Date.now() + SevenDaysMs) / 1000)

if (isAllowed) {
execute([poolId, [], [[validAddress, { TrancheInvestor: [trancheId, OneHundredYearsFromNow] }]]])
} else {
execute([poolId, [[validAddress, { TrancheInvestor: [trancheId, SevenDaysFromNow] }]], []])
}
setPendingTrancheId(trancheId)
}

return (
<PageSection
title="Investor status"
subtitle="Display investor status, and add or remove from investor memberlist."
>
<Stack gap={2}>
<Grid columns={2} equalColumns gap={4} alignItems="center">
<SearchInput
value={address}
onChange={(e) => setAddress(e.target.value)}
placeholder="Enter address..."
clear={() => setAddress('')}
/>
{address && !validAddress ? (
<Text variant="label2" color="statusCritical">
<Shelf gap={1}>
<IconInfoFailed size="20px" />
<span>Invalid address</span>
</Shelf>
</Text>
) : (
validAddress &&
(allowedTranches.length ? (
<Text variant="label2" color="statusOk">
<Shelf gap={1}>
<IconCheckCircle size="20px" />
<span>Address added to memberlist</span>
</Shelf>
</Text>
) : permissions && !allowedTranches.length ? (
<Text variant="label2" color="statusWarning">
<Shelf gap={1}>
<IconAlertCircle size="20px" />
<span>Address not in memberlist</span>
</Shelf>
</Text>
) : null)
)}
</Grid>
{pool?.tranches && validAddress && permissions && (
<DataTable
data={pool.tranches}
columns={[
{
align: 'left',
header: 'Token',
cell: (row: Token) => (
<Text textOverflow="ellipsis" variant="body2">
{row.currency.name}
</Text>
),
flex: '1',
},
{
align: 'left',
header: 'Investment',
cell: (row: Token) => <InvestedCell address={validAddress} poolId={poolId} trancheId={row.id} />,
flex: '1',
},
{
header: '',
align: 'right',
cell: (row: Token) => {
const isAllowed = allowedTranches.includes(row.id)

return (
<Button
variant="tertiary"
icon={isAllowed ? IconMinus : IconPlus}
onClick={() => toggleAllowed(row.id)}
loading={isTransactionPending && pendingTrancheId === row.id}
small
>
{isAllowed ? 'Remove from memberlist' : 'Add to memberlist'}
</Button>
)
},
flex: '1',
},
]}
/>
)}
</Stack>
</PageSection>
)
}

const InvestedCell: React.FC<{ address: string; poolId: string; trancheId: string }> = ({
poolId,
trancheId,
address,
}) => {
const order = useOrder(poolId, trancheId, address)
const balances = useBalances(address)
const hasBalance = balances && findBalance(balances.tranches, { Tranche: [poolId, trancheId] })
const hasOrder = order && (order?.submittedAt > 0 || !order.invest.isZero())
const hasInvested = hasBalance || hasOrder

return <TextWithPlaceholder variant="body2">{hasInvested && 'Invested'}</TextWithPlaceholder>
}
Loading

0 comments on commit 6542786

Please sign in to comment.