Skip to content

Commit

Permalink
feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
kattylucy committed Dec 5, 2024
1 parent 65d29c5 commit 6b049e0
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 89 deletions.
25 changes: 11 additions & 14 deletions centrifuge-app/src/components/FieldWithErrorMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, URLInput } from '@centrifuge/fabric'
import { URLInput } from '@centrifuge/fabric'
import { Field, FieldAttributes, useField, useFormikContext } from 'formik'
import * as React from 'react'

Expand All @@ -15,20 +15,17 @@ export function FieldWithErrorMessage(props: Props) {
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
form.setFieldValue(field.name, event.target.value)
}

return props.isUrl ? (
<Box>
<URLInput
label={props.label}
prefix={props.prefix}
value={field.value}
onChange={handleChange}
name={field.name}
placeholder={props.placeholder}
disabled={props.disabled}
errorMessage={meta.touched && meta.error ? meta.error : undefined}
/>
</Box>
<URLInput
label={props.label}
prefix={props.prefix}
value={field.value}
onChange={handleChange}
name={field.name}
placeholder={props.placeholder}
disabled={props.disabled}
errorMessage={meta.touched && meta.error ? meta.error : undefined}
/>
) : (
<Field errorMessage={meta.touched ? meta.error : undefined} {...props} />
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export const PoolDetailsSection = () => {
const form = useFormikContext<PoolMetadataInput>()
const createLabel = (label: string) => `${label}${isTestEnv ? '' : '*'}`

console.log(form.values)

return (
<Box>
<Text variant="heading2" fontWeight={700}>
Expand Down
2 changes: 1 addition & 1 deletion centrifuge-app/src/pages/IssuerCreatePool/PoolRatings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const PoolRatingsSection = () => {
</Field>

<Field name={`poolRatings.${index}.reportUrl`}>
{({ field, meta }: FieldProps) => (
{({ field }: FieldProps) => (
<FieldWithErrorMessage
{...field}
as={TextInput}
Expand Down
104 changes: 61 additions & 43 deletions centrifuge-app/src/pages/IssuerCreatePool/PoolSetupSection.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addressToHex, evmToSubstrateAddress, PoolMetadataInput } from '@centrifuge/centrifuge-js'
import { evmToSubstrateAddress, PoolMetadataInput } from '@centrifuge/centrifuge-js'
import { useCentEvmChainId } from '@centrifuge/centrifuge-react'
import {
Box,
Expand All @@ -22,6 +22,7 @@ import { feeCategories } from '../../../src/config'
import { isEvmAddress } from '../../../src/utils/address'
import { AddButton } from './PoolDetailsSection'
import { CheckboxOption, Line, StyledGrid } from './PoolStructureSection'
import { validate } from './validate'

const FEE_TYPES = [
{ label: 'Direct charge', value: 'chargedUpTo' },
Expand Down Expand Up @@ -96,15 +97,16 @@ export const PoolSetupSection = () => {
{values.adminMultisigEnabled ? (
values.adminMultisig?.signers?.map((_, index) => (
<Box key={index} mt={2}>
<Field name={`adminMultisig.signers.${index}`}>
{({ field, form }: FieldProps) => (
<TextInput
<Field name={`adminMultisig.signers.${index}`} validate={validate.addressValidate}>
{({ field, form, meta }: FieldProps) => (
<FieldWithErrorMessage
placeholder="Type address..."
{...field}
onChange={(val) => {
onChange={(val: React.ChangeEvent<HTMLInputElement>) => {
form.setFieldValue(`adminMultisig.signers.${index}`, val.target.value)
}}
onBlur={() => {
form.setFieldTouched(`adminMultisig.signers.${index}`, true)
const value = form.values.adminMultisig.signers[index]
if (value) {
const transformedValue = isEvmAddress(value)
Expand All @@ -113,15 +115,24 @@ export const PoolSetupSection = () => {
form.setFieldValue(`adminMultisig.signers.${index}`, transformedValue)
}
}}
errorMessage={meta.touched && meta.error ? meta.error : undefined}
as={TextInput}
/>
)}
</Field>
</Box>
))
) : (
<Box mt={2}>
<Field name={`adminMultisig.signers.0`}>
{({ field }: FieldProps) => <TextInput placeholder="Type address..." {...field} />}
<Field name={`adminMultisig.signers.0`} validate={validate.addressValidate}>
{({ field }: FieldProps) => (
<FieldWithErrorMessage
as={TextInput}
placeholder="Type address..."
{...field}
onBlur={field.onBlur}
/>
)}
</Field>
</Box>
)}
Expand Down Expand Up @@ -187,23 +198,17 @@ export const PoolSetupSection = () => {
<Text variant="heading2">Originate assets and invest in the pool*</Text>
{values.assetOriginators?.map((_: string, index: number) => (
<Box key={index} mt={2}>
<Field name={`assetOriginators.${index}`}>
{({ field, form }: FieldProps) => (
<TextInput
<Field name={`assetOriginators.${index}`} validate={validate.addressValidate}>
{({ field, form, meta }: FieldProps) => (
<FieldWithErrorMessage
placeholder="Type address..."
{...field}
onChange={(val) => {
onChange={(val: React.ChangeEvent<HTMLInputElement>) => {
form.setFieldValue(`assetOriginators.${index}`, val.target.value)
}}
onBlur={() => {
const value = form.values.assetOriginators[index]
if (value) {
const transformedValue = isEvmAddress(value)
? evmToSubstrateAddress(value, chainId ?? 0)
: addressToHex(value)
form.setFieldValue(`assetOriginators.${index}`, transformedValue)
}
}}
errorMessage={meta.touched && meta.error ? meta.error : undefined}
as={TextInput}
onBlur={field.onBlur}
/>
)}
</Field>
Expand Down Expand Up @@ -385,34 +390,47 @@ export const PoolSetupSection = () => {
</Box>
{values.onboardingExperience === 'centrifuge' && (
<Box>
<Box>
{values.tranches.map((tranche, index) => (
<Field key={index} name={`onboarding.tranches.${tranche.tokenName}`}>
{({ field, meta }: FieldProps) => (
<Box mb={4}>
<FileUpload
name={`onboarding.${tranche.tokenName}`}
file={field.value}
onFileChange={async (file) => {
form.setFieldTouched(`onboarding.tranches.${tranche.tokenName}`, true, false)
form.setFieldValue(`onboarding.tranches.${tranche.tokenName}`, file)
}}
label={`Subscription document for ${tranche.tokenName}`}
errorMessage={meta.touched && meta.error ? meta.error : undefined}
accept="application/pdf"
small
/>
</Box>
)}
</Field>
))}
</Box>
{values.tranches.map((tranche, index) => (
<Field
key={index}
name={`onboarding.tranches.${tranche.tokenName}`}
validate={validate.executiveSummary}
>
{({ field, meta }: FieldProps) => (
<Box mb={4}>
<FileUpload
name={`onboarding.${tranche.tokenName}`}
file={field.value}
onFileChange={async (file) => {
form.setFieldTouched(`onboarding.tranches.${tranche.tokenName}`, true, false)
form.setFieldValue(`onboarding.tranches.${tranche.tokenName}`, file)
}}
label={`Subscription document for ${tranche.tokenName}`}
errorMessage={meta.touched && meta.error ? meta.error : undefined}
accept="application/pdf"
small
onBlur={field.onBlur}
/>
</Box>
)}
</Field>
))}
<TaxDocument />
</Box>
)}
{values.onboardingExperience === 'external' && (
<Box>
<Field as={TextInput} name="onboarding.externalOnboardingUrl" label="External onboarding URL" />
<Field name="onboarding.externalOnboardingUrl" validate={validate.externalOnboardingUrl}>
{({ field, meta }: FieldProps) => (
<FieldWithErrorMessage
{...field}
onBlur={field.onBlur}
errorMessage={meta.touched && meta.error ? meta.error : undefined}
as={TextInput}
label="External onboarding url"
/>
)}
</Field>
<TaxDocument />
</Box>
)}
Expand Down
58 changes: 34 additions & 24 deletions centrifuge-app/src/pages/IssuerCreatePool/PoolStructureSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
CurrencyInput,
Grid,
IconHelpCircle,
InputErrorMessage,
NumberInput,
Select,
Text,
Expand Down Expand Up @@ -290,7 +291,7 @@ export const PoolStructureSection = () => {
<Grid gridTemplateColumns={['1fr', '1fr 1fr']} gap={3}>
<Box>
<Field name={`tranches.${index}.tokenName`}>
{({ field, form }: FieldProps) => (
{({ field, form, meta }: FieldProps) => (
<TextInput
{...field}
label="Token name"
Expand All @@ -305,35 +306,44 @@ export const PoolStructureSection = () => {
</Field>
<Box mt={3}>
<Field name={`tranches.${index}.minInvestment`} validate={validate.minInvestment}>
{({ field, form, meta }: FieldProps) => (
<CurrencyInput
{...field}
label={
<Tooltips type="minimumInvestment" label={<Text variant="heading4">Min. investment*</Text>} />
}
placeholder="0.00"
currency={values.assetDenomination}
errorMessage={meta.touched ? meta.error : undefined}
onChange={(value) => form.setFieldValue(field.name, value)}
onBlur={() => form.setFieldTouched(field.name, true)}
/>
)}
{({ field, form, meta }: FieldProps) => {
return (
<CurrencyInput
{...field}
label={
<Tooltips
type="minimumInvestment"
label={<Text variant="heading4">Min. investment*</Text>}
/>
}
placeholder="0.00"
currency={values.assetDenomination}
errorMessage={meta.touched ? meta.error : undefined}
onChange={(value) => form.setFieldValue(field.name, value)}
onBlur={() => form.setFieldTouched(field.name, true)}
/>
)
}}
</Field>
</Box>
</Box>

<Box>
<Field name={`tranches.${index}.symbolName`} validate={validate.symbolName}>
{({ field, form, meta }: FieldProps) => (
<TextInput
{...field}
onChange={(e) => form.setFieldValue(field.name, e.target.value)}
errorMessage={meta.touched ? meta.error : undefined}
label={<Tooltips type="tokenSymbol" label={<Text variant="heading4">Token symbol*</Text>} />}
placeholder="4-12 characters"
minLength={4}
maxLength={12}
/>
<Box position="relative">
<TextInput
{...field}
onChange={(e) => form.setFieldValue(field.name, e.target.value)}
label={<Tooltips type="tokenSymbol" label={<Text variant="heading4">Token symbol*</Text>} />}
placeholder="4-12 characters"
minLength={4}
maxLength={12}
/>
{meta.touched ? (
<InputErrorMessage style={{ position: 'absolute' }}>{meta.error}</InputErrorMessage>
) : null}
</Box>
)}
</Field>

Expand Down Expand Up @@ -378,7 +388,7 @@ export const PoolStructureSection = () => {
</Box>
</Box>

{(index === 1 || index === 2) && (
{index !== 0 && (
<>
<Box>
<Field name={`tranches.${index}.interestRate`} validate={validate.interestRate}>
Expand Down
16 changes: 12 additions & 4 deletions centrifuge-app/src/pages/IssuerCreatePool/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,19 @@ export const createPoolFee = (): PoolFee => ({

export type CreatePoolValues = Omit<
PoolMetadataInput,
'poolIcon' | 'issuerLogo' | 'executiveSummary' | 'adminMultisig' | 'poolFees' | 'poolReport' | 'poolRatings'
| 'poolIcon'
| 'issuerLogo'
| 'executiveSummary'
| 'adminMultisig'
| 'poolFees'
| 'poolReport'
| 'poolRatings'
| 'issuerName'
| 'epochHours'
| 'epochMinutes'
> & {
// pool structure
issuerName: null | ''
assetDenomination: string

// pool details
Expand Down Expand Up @@ -87,7 +97,7 @@ export const initialValues: CreatePoolValues = {
poolIcon: null,
maxReserve: 1000000,
investorType: '',
issuerName: '',
issuerName: null,
issuerRepName: '',
issuerLogo: null,
issuerDescription: '',
Expand Down Expand Up @@ -118,6 +128,4 @@ export const initialValues: CreatePoolValues = {
taxInfoRequired: false,
},
onboardingExperience: 'none',
epochHours: 0,
epochMinutes: 0,
}
15 changes: 15 additions & 0 deletions centrifuge-app/src/pages/IssuerCreatePool/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ export const validate = {
days: combine(required(), integer(), nonNegativeNumber(), max(Number.MAX_SAFE_INTEGER)),
writeOff: combine(required(), positiveNumber(), max(100)),
penaltyInterest: combine(required(), nonNegativeNumber(), max(100)),

addressValidate: required(),
externalOnboardingUrl: required(),
}

export const validateValues = (values: CreatePoolValues) => {
Expand Down Expand Up @@ -112,6 +115,18 @@ export const validateValues = (values: CreatePoolValues) => {
}
})

values.assetOriginators.forEach((asset, i) => {
if (!isSubstrateAddress(asset) && asset !== '') {
errors = setIn(errors, `assetOriginators.${i}`, 'Invalid address')
}
})

values.adminMultisig.signers.forEach((signer, i) => {
if (!isSubstrateAddress(signer) && signer !== '') {
errors = setIn(errors, `adminMultisig.signers.${i}`, 'Invalid address')
}
})

values.tranches.forEach((t, i) => {
if (tokenNames.has(t.tokenName)) {
errors = setIn(errors, `tranches.${i}.tokenName`, 'Tranche names must be unique')
Expand Down
4 changes: 2 additions & 2 deletions fabric/src/components/InputUnit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ export function InputLabel({
)
}

export function InputErrorMessage({ children }: { children: React.ReactNode }) {
export function InputErrorMessage({ children, style }: { children: React.ReactNode; style: React.CSSProperties }) {
return (
<Text variant="label2" color="statusCritical">
<Text variant="label2" color="statusCritical" style={{ ...style }}>
{children}
</Text>
)
Expand Down
1 change: 0 additions & 1 deletion fabric/src/components/TextInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ export function URLInput({
}: URLInputProps) {
const defaultId = React.useId()
id ??= defaultId

return (
<InputUnit
id={id}
Expand Down

0 comments on commit 6b049e0

Please sign in to comment.