Skip to content

Commit

Permalink
feat(kyc): Support PersonalDataAndDocumentsDetailed (#35)
Browse files Browse the repository at this point in the history
Support PersonalDataAndDocumentsDetailed
  • Loading branch information
jophish authored Feb 20, 2024
1 parent cfb94d5 commit 1131a20
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 6 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ For more information on these requirements, you may consult these resources:
### Fiat Account Schemas supported

- [x] [AccountNumber](https://github.com/fiatconnect/specification/blob/main/fiatconnect-api.md#9321-accountnumber)
- [ ] [MobileMoney](https://github.com/fiatconnect/specification/blob/main/fiatconnect-api.md#9322-mobilemoney)
- [x] [MobileMoney](https://github.com/fiatconnect/specification/blob/main/fiatconnect-api.md#9322-mobilemoney)
- [ ] [DuniaWallet](https://github.com/fiatconnect/specification/blob/main/fiatconnect-api.md#9323-duniawallet)
- [ ] [IBANNumber](https://github.com/fiatconnect/specification/blob/main/fiatconnect-api.md#9324-ibannumber)
- [ ] [IFSCAccount](https://github.com/fiatconnect/specification/blob/main/fiatconnect-api.md#9325-ifscaccount)
Expand All @@ -32,7 +32,7 @@ For more information on these requirements, you may consult these resources:
### KYC Schemas supported

- [x] [PersonalDataAndDocuments](https://github.com/fiatconnect/specification/blob/main/fiatconnect-api.md#9311-personaldataanddocuments)
- [ ] [PersonalDataAndDocumentsDetailed]()
- [x] [PersonalDataAndDocumentsDetailed](https://github.com/fiatconnect/specification/blob/main/fiatconnect-api.md#9312-personaldataanddocumentsdetailed)

### Transfer Types supported

Expand Down
7 changes: 6 additions & 1 deletion src/components/KYCInfoFieldSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,12 @@ function KYCInfoFieldSection({
title={fieldMetadata.displayInfo?.title ?? ''}
placeholder={fieldMetadata.displayInfo?.placeholder ?? ''}
onChange={(value) => setKycInfoWrapper({ [field]: value })}
value={getFieldValue(field) ?? ''}
value={
(fieldMetadata.reverseFormatter
? fieldMetadata.reverseFormatter(getFieldValue(field))
: getFieldValue(field)) ?? ''
}
allowedValues={fieldMetadata.choices ?? undefined}
/>
)
})}
Expand Down
15 changes: 13 additions & 2 deletions src/components/KYCInfoScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,23 @@ import {
providerIdToProviderName,
} from '../constants'
import KYCInfoFieldSection from './KYCInfoFieldSection'
import { personalDataAndDocumentsSchemaMetadata } from './kycInfo/PersonalDataAndDocuments'
import { useFiatConnectConfig } from '../hooks'
import { addKyc } from '../FiatConnectClient'
import { KycPending } from './kycStatusScreens/KycPending'
import { KycDenied } from './kycStatusScreens/KycDenied'
import { KycExpired } from './kycStatusScreens/KycExpired'
import { KycFieldMetadata } from '../types'
import { personalDataAndDocumentsSchemaMetadata } from './kycInfo/PersonalDataAndDocuments'
import { personalDataAndDocumentsDetailedSchemaMetadata } from './kycInfo/PersonalDataAndDocumentsDetailed'

const kycSchemaToMetadata: Record<
KycSchema,
Record<KycSchema, KycFieldMetadata>
> = {
[KycSchema.PersonalDataAndDocuments]: personalDataAndDocumentsSchemaMetadata,
[KycSchema.PersonalDataAndDocumentsDetailed]:
personalDataAndDocumentsDetailedSchemaMetadata,
}

interface Props {
kycStatus: KycStatus | undefined
Expand Down Expand Up @@ -112,7 +123,7 @@ export function KYCInfoScreen({
kycInfo={kycInfo}
setKycInfo={setKycInfoWrapper}
setSubmitDisabled={setSubmitDisabled}
kycSchemaMetadata={personalDataAndDocumentsSchemaMetadata}
kycSchemaMetadata={kycSchemaToMetadata[params.kycSchema]}
/>
</div>
<div id="KYCBottomSection">
Expand Down
206 changes: 206 additions & 0 deletions src/components/kycInfo/PersonalDataAndDocumentsDetailed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { KycFieldMetadata } from '../../types'
import { IdentificationDocumentType } from '@fiatconnect/fiatconnect-types'
import { Buffer } from 'buffer'

enum IdTypeFriendlyName {
IDC = 'Statue-issued ID',
PAS = 'Passport',
DL = `Driver's License`,
}

function idTypeFormatter(friendlyName: string): string {
switch (friendlyName) {
case IdTypeFriendlyName.IDC: {
return IdentificationDocumentType.IDC
}
case IdTypeFriendlyName.PAS: {
return IdentificationDocumentType.PAS
}
case IdTypeFriendlyName.DL: {
return IdentificationDocumentType.DL
}
default:
return ''
}
}

function idTypeReverseFormatter(idType: string | undefined): string {
switch (idType) {
case IdentificationDocumentType.IDC: {
return IdTypeFriendlyName.IDC
}
case IdentificationDocumentType.PAS: {
return IdTypeFriendlyName.PAS
}
case IdentificationDocumentType.DL: {
return IdTypeFriendlyName.DL
}
default:
return ''
}
}
const b64Encode = (input: string) => Buffer.from(input).toString('base64')

export const personalDataAndDocumentsDetailedSchemaMetadata: Record<
string,
KycFieldMetadata
> = {
firstName: {
required: true,
userField: true,
displayInfo: {
title: 'First Name',
placeholder: 'Your First Name',
},
},
lastName: {
required: true,
userField: true,
displayInfo: {
title: 'Last Name',
placeholder: 'Your Last Name',
},
},
day: {
required: true,
userField: true,
displayInfo: {
title: 'Day of Birth',
placeholder: 'DD',
},
group: 'dateOfBirth',
},
month: {
required: true,
userField: true,
displayInfo: {
title: 'Month of Birth',
placeholder: 'MM',
},
group: 'dateOfBirth',
},
year: {
required: true,
userField: true,
displayInfo: {
title: 'Year of Birth',
placeholder: 'YYYY',
},
group: 'dateOfBirth',
},
address1: {
required: true,
userField: true,
displayInfo: {
title: 'Address Line 1',
placeholder: 'Your Address',
},
group: 'address',
},
address2: {
required: false,
userField: true,
displayInfo: {
title: 'Address Line 2',
placeholder: 'Your Address',
},
group: 'address',
},
city: {
required: true,
userField: true,
displayInfo: {
title: 'City',
placeholder: 'Your city',
},
group: 'address',
},
isoRegionCode: {
required: true,
userField: true,
displayInfo: {
title: 'Region',
placeholder: 'Your region',
},
group: 'address',
},
isoCountryCode: {
required: true,
userField: true,
displayInfo: {
title: 'Country',
placeholder: 'Your country',
},
group: 'address',
},
postalCode: {
required: true,
userField: true,
displayInfo: {
title: 'Postal Code',
placeholder: 'Your postal code',
},
group: 'address',
},
phoneNumber: {
required: true,
userField: true,
displayInfo: {
title: 'Phone Number',
placeholder: 'Your phone number',
},
// TODO(M3): validation and formatting
},
email: {
required: true,
userField: true,
displayInfo: {
title: 'Email',
placeholder: 'Your email address',
},
// TODO(M3): validation and formatting
},
selfieDocument: {
required: true,
userField: true,
displayInfo: {
title: 'Selfie Photo',
placeholder: 'Please upload a clear image of yourself facing the camera',
},
photo: true,
formatter: b64Encode,
},
identificationDocumentType: {
required: true,
userField: true,
displayInfo: {
title: 'ID Document Type',
placeholder: 'Your ID type',
},
choices: Object.values(IdTypeFriendlyName) as [string, ...string[]],
formatter: idTypeFormatter,
reverseFormatter: idTypeReverseFormatter,
},
identificationDocumentFront: {
required: true,
userField: true,
displayInfo: {
title: 'ID Photo Front',
placeholder:
'Please upload a clear image of the front of your identification document',
},
photo: true,
formatter: b64Encode,
},
identificationDocumentBack: {
required: true,
userField: true,
displayInfo: {
title: 'ID Photo Back',
placeholder:
'Please upload a clear image of the back of your identification document',
},
photo: true,
formatter: b64Encode,
},
}
7 changes: 6 additions & 1 deletion src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ export const queryParamsSchema = z.object({
FiatAccountSchema.AccountNumber,
FiatAccountSchema.MobileMoney,
]),
kycSchema: z.enum([KycSchema.PersonalDataAndDocuments]).optional(),
kycSchema: z
.enum([
KycSchema.PersonalDataAndDocuments,
KycSchema.PersonalDataAndDocumentsDetailed,
])
.optional(),
userActionDetailsSchema: z
.enum([TransferInUserActionDetails.AccountNumberUserAction])
.optional(),
Expand Down
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ export interface FiatAccountFieldMetadata {
export interface KycFieldMetadata extends FiatAccountFieldMetadata {
group?: string // e.g. dateOfBirth, address
photo?: boolean
choices?: [string, ...string[]]
// A "reverse formatter" is needed when the choices displayed to a user in a dropdown
// are not the direct values sent in the form data, in order for the dropdown
// to "know" which value is selected.
reverseFormatter?: (input: string | undefined) => string
}

export enum Screens {
Expand Down

0 comments on commit 1131a20

Please sign in to comment.