onfido-sdk-ui
Version:
JavaScript SDK view layer for Onfido identity verification
126 lines (106 loc) • 3.02 kB
JavaScript
// @flow
import * as React from 'react'
import { h, Component } from 'preact'
import Visibility from 'visibilityjs'
import { screenshot } from '../utils/camera.js'
import { DocumentOverlay } from '../Overlay'
import Camera from '../Camera'
import CameraError from '../CameraError'
import { randomId } from '~utils/string'
import { postToBackend } from '../utils/sdkBackend';
const maxAttempts = 3
const serverError = { name: 'SERVER_ERROR', type: 'error' }
type Capture = {
id: string,
base64: string,
valid?: boolean,
processed?: boolean,
}
type State = {
hasError: boolean,
captures: Capture[],
}
type Props = {
token: string,
onValidCapture: Function,
onError: Function,
renderFallback: Function,
trackScreen: Function,
}
export default class DocumentAutoCapture extends Component<Props, State> {
webcam = null
interval: ?Visibility
state: State = {
hasError: false,
captures: [],
}
componentDidMount () {
this.start()
}
componentWillUnmount () {
this.stop()
}
screenshot = () => screenshot(this.webcam, this.handleScreenshot)
start() {
this.stop()
this.interval = Visibility.every(1000, this.screenshot)
}
stop() {
Visibility.stop(this.interval)
}
handleScreenshot = (blob: Blob, base64: string) => {
if (this.unprocessed().length < maxAttempts) {
const id = randomId()
const capture: Capture = { id, base64 }
this.setState({
captures: [capture, ...this.state.captures].slice(0, maxAttempts),
})
this.validate(base64, id, valid =>
valid ? this.props.onValidCapture({ blob, base64, id }) : null
)
} else {
console.warn('Server response is slow, waiting for responses before uploading more')
}
}
unprocessed = (): Capture[] => this.state.captures.filter(({ processed }) => !processed)
validate = (base64: string, id: string, callback: Function) => {
const { token } = this.props
const data = JSON.stringify({ image: base64, id })
postToBackend(data, token, ({ valid }) => {
this.setProcessed(id, !!valid)
callback(valid)
}, this.handleValidationError)
}
setProcessed(id: string, valid: boolean) {
const { captures } = this.state
const update = { valid: !!valid, processed: true }
this.setState({
captures: captures.map(capture => capture.id === id ? ({ ...capture, ...update }) : capture),
})
}
handleValidationError = () => {
this.setState({ hasError: true })
this.props.onError()
}
render() {
const { hasError } = this.state
const { trackScreen, renderFallback } = this.props
return (
<div>
<Camera
{...this.props}
webcamRef={ c => this.webcam = c }
renderError={ hasError ?
<CameraError
error={serverError}
{...{trackScreen, renderFallback}}
/> :
undefined
}
>
<DocumentOverlay />
</Camera>
</div>
)
}
}