onfido-sdk-ui
Version:
JavaScript SDK view layer for Onfido identity verification
309 lines (295 loc) • 7.77 kB
JavaScript
import { h, Component } from 'preact'
import { Button } from '@onfido/castor-react'
import classNames from 'classnames'
import { isDesktop } from '~utils'
import { camelCase } from '~utils/string'
import { validateFile } from '~utils/file'
import { isButtonGroupStacked } from '../Theme/utils'
import { trackComponentAndMode } from '../../Tracker'
import { localised } from '../../locales'
import CustomFileInput from '../CustomFileInput'
import PageTitle from '../PageTitle'
import UploadError from './Error'
import theme from '../Theme/style.scss'
import style from './style.scss'
const MobileUploadArea = ({
onFileSelected,
children,
isPoA,
translate,
isUploading,
}) => (
<div className={style.uploadArea}>
{children}
<div
className={classNames(style.buttons, {
[style.poaButtons]: isPoA,
[style.vertical]: isButtonGroupStacked(),
})}
>
<CustomFileInput
className={classNames({
[style.buttonContainer]: !isPoA,
[style.poaBtn]: isPoA,
[style.vertical]: isButtonGroupStacked(),
})}
onChange={onFileSelected}
accept="image/*"
capture
>
<Button
variant={isPoA ? 'secondary' : 'primary'}
className={
isPoA
? classNames(theme['button-sm'], {
[theme.vertical]: isButtonGroupStacked(),
})
: classNames(theme['button-centered'], theme['button-lg'])
}
disabled={isUploading}
>
{translate('photo_upload.button_take_photo')}
</Button>
</CustomFileInput>
{isPoA && (
<CustomFileInput
onChange={onFileSelected}
className={classNames({ [style.poaBtn]: isPoA })}
>
<Button
variant="primary"
className={classNames(theme['button-sm'], {
[theme.vertical]: isButtonGroupStacked(),
})}
disabled={isUploading}
>
{translate(
isDesktop
? 'doc_submit.button_link_upload'
: 'photo_upload.button_upload'
)}
</Button>
</CustomFileInput>
)}
</div>
</div>
)
const PassportMobileUploadArea = ({
nextStep,
children,
translate,
isUploading,
}) => (
<div className={style.uploadArea}>
{children}
<div className={style.buttons}>
<Button
variant="primary"
className={classNames(theme['button-centered'], theme['button-lg'])}
disabled={isUploading}
onClick={nextStep}
>
{translate('photo_upload.button_take_photo')}
</Button>
</div>
</div>
)
const DesktopUploadArea = ({
translate,
uploadType,
changeFlowTo,
mobileFlow,
children,
isUploading,
}) => (
<div className={style.crossDeviceInstructionsContainer}>
<div className={style.iconContainer}>
<i
className={classNames(
theme.icon,
style.icon,
style[`${camelCase(uploadType)}Icon`]
)}
/>
</div>
<div>
{!mobileFlow && ( // Hide for mobileFlow on desktop browser as `test` Node environment has restrictedXDevice set to false
<Button
variant="primary"
className={classNames(
theme['button-centered'],
theme['button-lg'],
style.crossDeviceButton
)}
onClick={() => changeFlowTo('crossDeviceSteps')}
disabled={isUploading}
>
{translate('doc_submit.button_primary')}
</Button>
)}
{children}
</div>
</div>
)
const PassportUploadIntro = ({
changeFlowTo,
uploadType,
instructions,
translate,
mobileFlow,
nextStep,
}) => {
if (isDesktop) {
return (
<DesktopUploadArea
translate={translate}
uploadType={uploadType}
changeFlowTo={changeFlowTo}
mobileFlow={mobileFlow}
>
<button
type="button"
className={theme.link}
data-onfido-qa="uploaderButtonLink"
onClick={nextStep}
>
{translate('doc_submit.button_link_upload')}
</button>
</DesktopUploadArea>
)
}
return (
<PassportMobileUploadArea nextStep={nextStep} translate={translate}>
<div className={style.instructions}>
<div className={style.iconContainer}>
<span className={classNames(theme.icon, style.identityIcon)} />
</div>
<div className={style.instructionsCopy}>{instructions}</div>
</div>
</PassportMobileUploadArea>
)
}
const UploadArea = (props) => {
const {
changeFlowTo,
uploadType,
instructions,
translate,
mobileFlow,
error,
handleFileSelected,
isUploading,
} = props
const isPoA = uploadType === 'proof_of_address'
if (isDesktop) {
return (
<DesktopUploadArea
translate={translate}
uploadType={uploadType}
changeFlowTo={changeFlowTo}
mobileFlow={mobileFlow}
isUploading={isUploading}
>
<CustomFileInput onChange={handleFileSelected}>
{error && <UploadError {...{ error, translate }} />}
<button
type="button"
className={theme.link}
data-onfido-qa="uploaderButtonLink"
disabled={isUploading}
>
{translate('doc_submit.button_link_upload')}
</button>
</CustomFileInput>
</DesktopUploadArea>
)
}
return (
<MobileUploadArea
onFileSelected={handleFileSelected}
translate={translate}
{...{ isPoA, isUploading }}
>
<div className={style.instructions}>
<div
className={classNames(style.iconContainer, {
[style.poaIconContainer]: isPoA,
})}
>
<span
className={classNames(
theme.icon,
style.icon,
style[`${camelCase(uploadType)}Icon`]
)}
/>
</div>
{error ? (
<UploadError {...{ error, translate }} />
) : (
<div className={style.instructionsCopy}>{instructions}</div>
)}
</div>
</MobileUploadArea>
)
}
class Uploader extends Component {
static defaultProps = {
onUpload: () => {},
}
state = {
error: null,
isUploading: false,
}
setError = (name) => this.setState({ error: { name }, isUploading: false })
handleFileSelected = (file) => {
this.setState({
error: null,
isUploading: true,
})
validateFile(file, this.props.onUpload, this.setError)
}
render() {
const {
title,
subTitle,
allowCrossDeviceFlow,
translate,
documentType,
uploadType,
} = this.props
const isPassportUpload =
uploadType !== 'face' && documentType === 'passport'
return (
<div className={classNames(theme.fullHeightContainer, style.container)}>
<PageTitle
title={title}
subTitle={
allowCrossDeviceFlow ? translate('doc_submit.subtitle') : subTitle
}
/>
<div
className={classNames(style.uploaderWrapper, {
[style.crossDeviceClient]: !allowCrossDeviceFlow,
})}
>
{isPassportUpload ? (
<PassportUploadIntro {...this.props} />
) : (
<UploadArea
{...this.props}
error={this.state.error}
handleFileSelected={this.handleFileSelected}
isUploading={this.state.isUploading}
/>
)}
</div>
</div>
)
}
}
export default trackComponentAndMode(
localised(Uploader),
'file_upload',
'error'
)