Advanced Tutorial: KYC Plugin web views
We will go over how to develop home and verification web views for the KYC plugin.
Step 1: Initialize the KYC plugin web view.
Run the following commands to initialize the plugin web view:
cd web/
npm run add-plugin --plugin=kyc --type=kyc
Step 2: Install the initial plugin.
Run the following commands to build the initial plugin with a default view and install the plugin.
cd ..
npm run build --plugin=kyc
Step 3: disable CORS error on the browser.
The web view JSON file and bundles are served on the localhost port 8080. In order to allow the kit to access them in plugin development mode, we need to disable the CORS issue on the browser. This can be achieved by using a browser extension.
Step 4: Plugin interactive development mode
To start using interactive plugin development mode, we need to run the commands of steps 5 and 6 simultaneously.
Step 5: Create, watch and serve web view bundles and the JSON file.
Run the following command on the plugin starter kit web directory:
npm start --plugin=kyc
Step 6: Start Hollaex kit plugin development mode.
Run the following command on the Hollaex kit web directory:
npm run dev:plugin --plugin=kyc
In order to see the plugin's changes, we need to refresh the page after every change.
Step 7: Update home Form.js component.
Then add the following component to the Form.js file.
import React, { useState, useEffect } from 'react';
import { Tabs } from 'antd';
import { withKit } from 'components/KitContext';
import Identity from './components/Identity';
import Documents from './components/Documents';
const { TabPane } = Tabs;
const INITIAL_KYC_TAB_KEY = 'initial_kyc_tab';
const Form = ({ strings: STRINGS, setActivePageContent: setPageContent, handleBack, activeLanguage, user, getCountry, getFormatTimestamp, icons: ICONS }) => {
const kycTabs = [
{
key: 'identity',
title: STRINGS['USER_VERIFICATION.TITLE_IDENTITY'],
},
{
key: 'documents',
title: STRINGS['USER_VERIFICATION.TITLE_ID_DOCUMENTS'],
},
];
const [activeKYCTab, setActiveKYCTab] = useState('identity');
useEffect(() => {
const kycInitialTab = localStorage.getItem(INITIAL_KYC_TAB_KEY);
if (kycInitialTab && kycTabs.map(({key}) => key).includes(kycInitialTab)) {
setActiveKYCTab(kycInitialTab);
}
}, []);
const setActivePageContent = (key) => (page) => {
localStorage.setItem(INITIAL_KYC_TAB_KEY, key);
setPageContent(page)
}
const renderKYCVerificationHomeContent = (key, user, activeLanguage) => {
switch (key) {
case 'identity':
return (
<Identity
activeLanguage={activeLanguage}
user={user}
handleBack={handleBack}
setActivePageContent={setActivePageContent(key)}
getFormatTimestamp={getFormatTimestamp}
getCountry={getCountry}
strings={STRINGS}
/>
);
case 'documents':
return (
<Documents
user={user}
setActivePageContent={setActivePageContent(key)}
icons={ICONS}
strings={STRINGS}
/>
);
default:
return <div>No content</div>;
}
};
return (
<div>
<Tabs activeKey={activeKYCTab} onTabClick={setActiveKYCTab}>
{kycTabs.map(({ key, title }) => (
<TabPane tab={title} key={key}>
{renderKYCVerificationHomeContent(
key,
user,
activeLanguage
)}
</TabPane>
))}
</Tabs>
</div>
)
}
const mapContextToProps = ({ strings, setActivePageContent, handleBack, activeLanguage, user, getCountry, getFormatTimestamp, icons }) => ({
strings,
setActivePageContent,
handleBack,
activeLanguage,
user,
getCountry,
getFormatTimestamp,
icons,
});
export default withKit(mapContextToProps)(Form);
In this component, we are getting the following common props and target-specific props from the kit context using the withKit HOC.
Common props:
strings
,activeLanguage
,user
,icons
Target-specific props:
setActivePageContent
,handleBack
,getCountry
,getFormatTimestamp
See the SmartTarget with REMOTE_COMPONENT__KYC_VERIFICATION_HOME
id on the verification container component for more details about the props.
Step 8: Add home components.
mkdir src/plugins/kyc/views/home/components
touch src/plugins/kyc/views/home/components/Documents.js
touch src/plugins/kyc/views/home/components/Identity.js
Documents
import React from 'react';
import moment from 'moment';
import classnames from 'classnames';
import { Button, PanelInformationRow, Editable as EditWrapper, Image } from 'hollaex-web-lib';
const Documents = ({
user,
setActivePageContent,
icons: ICONS,
strings: STRINGS,
}) => {
const { id_data } = user;
let note = '';
if (id_data.status === 1) {
note = STRINGS['USER_VERIFICATION.DOCUMENT_PENDING_NOTE'];
} else if (id_data.status === 2) {
note = id_data.note;
} else {
note = STRINGS['USER_VERIFICATION.DOCUMENT_VERIFIED_NOTE'];
}
return (
<div>
{id_data.status !== 0 && (
<div className="d-flex my-3">
<div
className={classnames('mr-2', 'd-flex', 'justify-content-center', 'align-items-center')}
title={
STRINGS['USER_VERIFICATION.NOTE_FROM_VERIFICATION_DEPARTMENT']
}
>
<Image
icon={ICONS['NOTE_KYC']}
iconId="NOTE_KYC"
stringId="USER_VERIFICATION.NOTE_FROM_VERIFICATION_DEPARTMENT"
wrapperClassName="document-note-icon"
/>
</div>
<PanelInformationRow
stringId="USER_VERIFICATION.CUSTOMER_SUPPORT_MESSAGE,USER_VERIFICATION.DOCUMENT_PENDING_NOTE,USER_VERIFICATION.DOCUMENT_VERIFIED_NOTE"
label={STRINGS['USER_VERIFICATION.CUSTOMER_SUPPORT_MESSAGE']}
information={note}
className="title-font"
disable
/>
</div>
)}
{id_data.status === 1 && (
<div className="my-3">
<PanelInformationRow
stringId="USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.ID_NUMBER_LABEL"
label={
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.ID_NUMBER_LABEL'
]
}
information={id_data.number}
className="title-font"
disable
/>
<div className="d-flex">
<PanelInformationRow
stringId="USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.ISSUED_DATE_LABEL"
label={
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.ISSUED_DATE_LABEL'
]
}
information={moment(id_data.issued_date).format('DD, MMMM, YYYY')}
className="title-font mr-2"
disable
/>
<PanelInformationRow
stringId="USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.EXPIRATION_DATE_LABEL"
label={
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.EXPIRATION_DATE_LABEL'
]
}
information={moment(id_data.expiration_date).format(
'DD, MMMM, YYYY'
)}
className="title-font"
disable
/>
</div>
</div>
)}
{id_data.status !== 3 && (
<div className="my-2 btn-wrapper">
<div className="holla-verification-button static pt-4">
<EditWrapper stringId="USER_VERIFICATION.START_DOCUMENTATION_SUBMISSION,USER_VERIFICATION.START_DOCUMENTATION_RESUBMISSION" />
<Button
label={
id_data.status === 0
? STRINGS['USER_VERIFICATION.START_DOCUMENTATION_SUBMISSION']
: STRINGS[
'USER_VERIFICATION.START_DOCUMENTATION_RESUBMISSION'
]
}
onClick={() => setActivePageContent('kyc')}
/>
</div>
</div>
)}
</div>
);
};
export default Documents;
Identityocalhost:3000/hello-exchange.
import React from 'react';
import { Button, PanelInformationRow, Editable as EditWrapper } from 'hollaex-web-lib';
const formatBirthday = {
en: 'DD, MMMM, YYYY',
fa: 'jDD, jMMMM, jYYYY',
};
const Identity = ({
user,
activeLanguage,
setActivePageContent,
handleBack,
strings: STRINGS,
getCountry,
getFormatTimestamp,
}) => {
const { address, id_data } = user;
if (!address.country) {
return (
<div className="btn-wrapper">
<div className="holla-verification-button static pt-4">
<EditWrapper stringId="USER_VERIFICATION.START_IDENTITY_VERIFICATION" />
<Button
label={STRINGS['USER_VERIFICATION.START_IDENTITY_VERIFICATION']}
onClick={() => setActivePageContent('kyc')}
/>
</div>
</div>
);
} else {
return (
<div>
<div className="font-weight-bold text-lowercase">
{STRINGS.formatString(
STRINGS['USER_VERIFICATION.BANK_VERIFICATION_HELP_TEXT'],
<span
className="verification_link pointer"
onClick={(e) => handleBack('kyc', e)}
>
{STRINGS['USER_VERIFICATION.DOCUMENT_SUBMISSION']}
</span>
)}
<EditWrapper stringId="USER_VERIFICATION.BANK_VERIFICATION_HELP_TEXT,USER_VERIFICATION.DOCUMENT_SUBMISSION" />
</div>
<div className="my-3">
<PanelInformationRow
stringId="USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.FULL_NAME_LABEL"
label={
STRINGS[
'USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.FULL_NAME_LABEL'
]
}
information={user.full_name}
className="title-font"
disable
/>
<div className="d-flex">
<PanelInformationRow
stringId="USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.GENDER_LABEL,USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.GENDER_OPTIONS.MAN,USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.GENDER_OPTIONS.WOMAN"
label={
STRINGS[
'USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.GENDER_LABEL'
]
}
information={
user.gender === false
? STRINGS[
'USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.GENDER_OPTIONS.MAN'
]
: STRINGS[
'USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.GENDER_OPTIONS.WOMAN'
]
}
className="title-font divider"
disable
/>
<PanelInformationRow
stringId="USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.DOB_LABEL"
label={
STRINGS[
'USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.DOB_LABEL'
]
}
information={getFormatTimestamp(
user.dob,
formatBirthday[activeLanguage]
)}
className="title-font"
disable
/>
</div>
<PanelInformationRow
stringId="USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.NATIONALITY_LABEL"
label={
STRINGS[
'USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.NATIONALITY_LABEL'
]
}
information={getCountry(user.nationality).name}
className="title-font"
disable
/>
<div className="d-flex">
<PanelInformationRow
stringId="USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.COUNTRY_LABEL"
label={
STRINGS[
'USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.COUNTRY_LABEL'
]
}
information={getCountry(address.country).name}
className="title-font divider"
disable
/>
<PanelInformationRow
stringId="USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.CITY_LABEL"
label={
STRINGS[
'USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.CITY_LABEL'
]
}
information={address.city}
className="title-font"
disable
/>
</div>
<div className="d-flex">
<div className="w-75">
<PanelInformationRow
stringId="USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.ADDRESS_LABEL"
label={
STRINGS[
'USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.ADDRESS_LABEL'
]
}
information={address.address}
className="title-font divider"
disable
/>
</div>
<PanelInformationRow
stringId="USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.POSTAL_CODE_LABEL"
label={
STRINGS[
'USER_VERIFICATION.USER_DOCUMENTATION_FORM.FORM_FIELDS.POSTAL_CODE_LABEL'
]
}
information={address.postal_code}
className="title-font"
disable
/>
</div>
</div>
{id_data.status === 3 ? null : (
<div className="btn-wrapper">
<div className="holla-verification-button static pt-4">
<EditWrapper stringId="USER_VERIFICATION.REVIEW_IDENTITY_VERIFICATION" />
<Button
label={
STRINGS['USER_VERIFICATION.REVIEW_IDENTITY_VERIFICATION']
}
onClick={() => setActivePageContent('kyc')}
/>
</div>
</div>
)}
</div>
);
}
};
export default Identity;
Step 9: Update verification Form.js component.
import React, { useState, useEffect } from 'react';
import { Tabs } from 'antd';
import { withKit } from 'components/KitContext';
import Identity from './components/Identity';
import Documents from './components/Documents';
const { TabPane } = Tabs;
const INITIAL_KYC_TAB_KEY = 'initial_kyc_tab';
const Form = ({ handleBack: back, strings: STRINGS, user, constants, identityInitialValues, documentInitialValues }) => {
const kycTabs = [
{
key: 'identity',
title: STRINGS['USER_VERIFICATION.TITLE_IDENTITY'],
},
{
key: 'documents',
title: STRINGS['USER_VERIFICATION.TITLE_ID_DOCUMENTS'],
},
];
const [activeKYCTab, setActiveKYCTab] = useState('identity');
useEffect(() => {
const kycInitialTab = localStorage.getItem(INITIAL_KYC_TAB_KEY);
if (kycInitialTab && kycTabs.map(({key}) => key).includes(kycInitialTab)) {
setActiveKYCTab(kycInitialTab);
}
}, []);
const handleBack = (key) => (params) => {
localStorage.setItem(INITIAL_KYC_TAB_KEY, key);
back(params)
}
const renderKYCVerificationContent = (key) => {
switch (key) {
case 'identity':
return (
<Identity
fullName={user.full_name}
initialValues={identityInitialValues(user, constants)}
handleBack={handleBack(key)}
/>
);
case 'documents':
return (
<Documents
idData={user.id_data}
initialValues={documentInitialValues(user)}
handleBack={handleBack(key)}
/>
);
default:
return <div>No content</div>;
}
};
return (
<div className="presentation_container apply_rtl verification_container">
<Tabs activeKey={activeKYCTab} onTabClick={setActiveKYCTab}>
{kycTabs.map(({ key, title }) => (
<TabPane tab={title} key={key}>
{renderKYCVerificationContent(key)}
</TabPane>
))}
</Tabs>
</div>
)
}
const mapContextToProps = ({ handleBack, strings, user, constants, identityInitialValues, documentInitialValues }) => ({
handleBack,
strings,
user,
constants,
identityInitialValues,
documentInitialValues
});
export default withKit(mapContextToProps)(Form);
In this component, we are getting the following common and target-specific props from the kit context using the withKit HOC.
Common props:
strings
,user
,constants
Target-specific props:
handleBack
,identityInitialValues
,documentInitialValues
See the SmartTarget with REMOTE_COMPONENT__KYC_VERIFICATION
id on the verification container component for more details about the props.
Step 10: Add verification components.
mkdir src/plugins/kyc/views/verification/components
touch src/plugins/kyc/views/verification/components/Documents.js
touch src/plugins/kyc/views/verification/components/Identity.js
touch src/plugins/kyc/views/verification/components/HeaderSection.js
Documents
import React, { Component } from 'react';
import { reduxForm, SubmissionError, formValueSelector } from 'redux-form';
import { connect } from 'react-redux';
import moment from 'moment';
import {
isBefore,
requiredWithCustomMessage,
} from 'utils';
import { Button, IconTitle, Image, Editable } from 'hollaex-web-lib';
import { HeaderSection } from 'components/HeaderSection';
import { withKit } from 'components/KitContext';
import {
IdentificationFormSection,
PORSection,
SelfieWithPhotoId,
} from './HeaderSection';
import { isMobile } from 'react-device-detect';
const FORM_NAME = 'DocumentsVerification';
const selector = formValueSelector(FORM_NAME);
export const sizeLimitInMB = 6;
const sizeLimit = sizeLimitInMB * 1024 * 1024;
class Documents extends Component {
state = {
formFields: {},
accSize: 0,
};
componentDidMount() {
this.generateFormFields(this.props.activeLanguage);
}
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.activeLanguage !== this.props.activeLanguage) {
this.generateFormFields(nextProps.activeLanguage);
}
if (JSON.stringify(nextProps.files) !== JSON.stringify(this.props.files)) {
this.checkTotalFilesSize(nextProps.files)
}
}
getFileSize = (file) => {
if (file && file.size) {
return file.size;
} else {
return 0;
}
}
checkTotalFilesSize = (files = {}) => {
let accSize = 0
Object.entries(files).forEach(([_, file]) => {
accSize += this.getFileSize(file);
})
this.setState({ accSize });
}
generateFormFields = (language) => {
const { strings: STRINGS } = this.props;
const formFields = {
idDocument: {
number: {
type: 'text',
stringId:
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.ID_NUMBER_LABEL,USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.ID_NUMBER_PLACEHOLDER,USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.ID_NUMBER',
label:
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.ID_NUMBER_LABEL'
],
placeholder:
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.ID_NUMBER_PLACEHOLDER'
],
validate: [
requiredWithCustomMessage(
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.ID_NUMBER'
]
),
],
fullWidth: isMobile,
ishorizontalfield: true,
},
issued_date: {
type: 'date-dropdown',
stringId:
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.ISSUED_DATE_LABEL,USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.ISSUED_DATE',
label:
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.ISSUED_DATE_LABEL'
],
validate: [
requiredWithCustomMessage(
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.ISSUED_DATE'
]
),
isBefore('', STRINGS['VALIDATIONS.INVALID_DATE']),
],
endDate: moment().add(1, 'days'),
language,
fullWidth: isMobile,
ishorizontalfield: true,
},
expiration_date: {
type: 'date-dropdown',
stringId:
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.EXPIRATION_DATE_LABEL,USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.EXPIRATION_DATE',
label:
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.EXPIRATION_DATE_LABEL'
],
validate: [
requiredWithCustomMessage(
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.EXPIRATION_DATE'
]
),
isBefore(moment().add(15, 'years'), STRINGS['VALIDATIONS.INVALID_DATE']),
],
endDate: moment().add(15, 'years'),
addYears: 15,
yearsBefore: 5,
language,
fullWidth: isMobile,
ishorizontalfield: true,
},
},
id: {
type: {
type: 'hidden',
},
front: {
type: 'file',
stringId:
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.FRONT_LABEL,USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.FRONT_PLACEHOLDER,USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.FRONT',
label:
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.FRONT_LABEL'
],
placeholder:
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.FRONT_PLACEHOLDER'
],
validate: [
requiredWithCustomMessage(
STRINGS['USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.FRONT']
),
],
fullWidth: isMobile,
ishorizontalfield: true,
},
},
proof_of_residency: {
type: {
type: 'hidden',
},
back: {
type: 'file',
stringId:
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.POR_LABEL,USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.POR_PLACEHOLDER,USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.PROOF_OF_RESIDENCY',
label:
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.POR_LABEL'
],
placeholder:
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.POR_PLACEHOLDER'
],
validate: [
requiredWithCustomMessage(
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.PROOF_OF_RESIDENCY'
]
),
],
fullWidth: isMobile,
ishorizontalfield: true,
},
},
selfieWithNote: {
type: {
type: 'hidden',
},
proof_of_residency: {
type: 'file',
stringId:
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.SELFIE_PHOTO_ID_LABEL,USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.SELFIE_PHOTO_ID_PLACEHOLDER,USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.SELFIE_PHOTO_ID',
label:
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.SELFIE_PHOTO_ID_LABEL'
],
placeholder:
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.FORM_FIELDS.SELFIE_PHOTO_ID_PLACEHOLDER'
],
validate: [
requiredWithCustomMessage(
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.VALIDATIONS.SELFIE_PHOTO_ID'
]
),
],
fullWidth: isMobile,
ishorizontalfield: true,
},
},
};
this.setState({ formFields });
};
handleSubmit = (formValues) => {
const { moveToNextStep, setActivePageContent, updateDocuments } = this.props;
return updateDocuments(formValues)
.then(({ data }) => {
const values = {
type: formValues.type,
number: formValues.number,
expiration_date: formValues.expiration_date,
issued_date: formValues.issued_date,
status: 1,
};
moveToNextStep('documents', values);
setActivePageContent('email');
})
.catch((err) => {
const error = { _error: err.message };
if (err.response && err.response.data) {
error._error = err.response.data.message;
}
throw new SubmissionError(error);
});
};
onGoBack = () => {
const { setActivePageContent, handleBack } = this.props;
setActivePageContent('email');
handleBack('kyc');
};
render() {
const {
idData,
handleSubmit,
pristine,
submitting,
valid,
error,
// skip,
openContactForm,
icons: ICONS,
strings: STRINGS,
getErrorLocalized,
renderFields,
} = this.props;
const { formFields, accSize } = this.state;
const violated = accSize > sizeLimit;
return (
<div>
<IconTitle
stringId="USER_VERIFICATION.DOCUMENT_VERIFICATION"
text={STRINGS['USER_VERIFICATION.DOCUMENT_VERIFICATION']}
textType="title"
iconPath={ICONS['VERIFICATION_DOCUMENT_NEW']}
/>
<form
className="d-flex flex-column w-100 verification_content-form-wrapper"
onSubmit={this.handleSubmit}
>
<div className="verification-form-panel mt-3">
<HeaderSection
stringId="USER_VERIFICATION.DOCUMENT_PROOF_SUBMISSION"
title={STRINGS['USER_VERIFICATION.DOCUMENT_PROOF_SUBMISSION']}
openContactForm={openContactForm}
>
<IdentificationFormSection strings={STRINGS} />
</HeaderSection>
{renderFields(formFields.idDocument)}
{renderFields(formFields.id)}
</div>
<div className="my-4" />
<div className="verification-form-panel">
{formFields.proof_of_residency && (
<div>
<HeaderSection
stringId="USER_VERIFICATION.ID_DOCUMENTS_FORM.INFORMATION.PROOF_OF_RESIDENCY"
title={
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.INFORMATION.PROOF_OF_RESIDENCY'
]
}
>
<PORSection strings={STRINGS}/>
</HeaderSection>
{renderFields(formFields.proof_of_residency)}
</div>
)}
</div>
<div className="my-4" />
<div className="verification-form-panel">
{formFields.selfieWithNote && (
<div>
<HeaderSection
stringId="USER_VERIFICATION.ID_DOCUMENTS_FORM.INFORMATION.SELFIE.TITLE"
title={
STRINGS[
'USER_VERIFICATION.ID_DOCUMENTS_FORM.INFORMATION.SELFIE.TITLE'
]
}
>
<SelfieWithPhotoId strings={STRINGS} />
</HeaderSection>
<div className="my-2">
<Image
alt="document-sample"
iconId="SELF_KYC_ID_EN"
icon={ICONS['SELF_KYC_ID_EN']}
wrapperClassName="verification_document-sample"
/>
</div>
{renderFields(formFields.selfieWithNote)}
</div>
)}
</div>
{error && (
<div className="warning_text">{getErrorLocalized(error)}</div>
)}
{
violated && (
<div className="warning_text">
<Editable stringId="USER_VERIFICATION.ID_DOCUMENTS_FORM.INFORMATION.ID_SECTION.VIOLATION_ERROR">
{STRINGS.formatString(STRINGS['USER_VERIFICATION.ID_DOCUMENTS_FORM.INFORMATION.ID_SECTION.VIOLATION_ERROR'], sizeLimitInMB)}
</Editable>
</div>
)
}
<div className="my-4" />
<div className="d-flex justify-content-center">
<div className="d-flex justify-content-end f-1 verification-buttons-wrapper">
<Button
type="button"
onClick={this.onGoBack}
label={STRINGS['USER_VERIFICATION.GO_BACK']}
disabled={submitting}
/>
</div>
<div className="separator" />
<div className="d-flex flex-column f-1 verification-buttons-wrapper">
<div>
<Button
type="button"
onClick={handleSubmit(this.handleSubmit)}
label={
idData.status === 0
? STRINGS['SUBMIT']
: `${STRINGS['RESUBMIT']}*`
}
disabled={pristine || submitting || !valid || !!error || violated}
/>
</div>
{idData.status !== 0 && (
<span className="content-text">
{STRINGS['USER_VERIFICATION.SUBMISSION_PENDING_TXT']}
</span>
)}
</div>
</div>
</form>
</div>
);
}
}
const mapStateToProps = (state) => ({
files: selector(
state,
'front',
'back',
'proof_of_residency'
),
});
const mapContextToProps = ({ strings, setActivePageContent, moveToNextStep, activeLanguage, getErrorLocalized, icons, renderFields, updateDocuments, openContactForm }) => ({
strings,
setActivePageContent,
moveToNextStep,
activeLanguage,
getErrorLocalized,
icons,
renderFields,
updateDocuments,
openContactForm
});
const DocumentsForm = reduxForm({
form: FORM_NAME,
})(withKit(mapContextToProps)(Documents));
export default connect(mapStateToProps)(DocumentsForm);
See the SmartTarget with REMOTE_COMPONENT__KYC_VERIFICATION
id on the verification container component for more details about the props passed using the kit context.
Identity
import React, { Component } from 'react';
import moment from 'moment';
import { reduxForm, SubmissionError } from 'redux-form';
import {
requiredWithCustomMessage as required,
requiredBoolean,
isBefore,
} from 'utils';
import { Button, IconTitle, Editable as EditWrapper } from 'hollaex-web-lib';
import { HeaderSection } from 'components/HeaderSection';
import { withKit } from 'components/KitContext';
import { isMobile } from 'react-device-detect';
const FORM_NAME = 'IdentityVerification';
class IdentityVerification extends Component {
state = {
formFields: {}