Skip to content

Commit

Permalink
feat(Onfido): Add back onfido
Browse files Browse the repository at this point in the history
  • Loading branch information
plondon committed Dec 14, 2018
1 parent f1c2889 commit c1b7e31
Show file tree
Hide file tree
Showing 18 changed files with 350 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as layoutWallet from './layoutWallet/actionTypes'
import * as lockbox from './lockbox/actionTypes'
import * as login from './login/actionTypes'
import * as manageAddresses from './manageAddresses/actionTypes'
import * as onfido from './onfido/actionTypes'
import * as priceChart from './priceChart/actionTypes'
import * as priceTicker from './priceTicker/actionTypes'
import * as refresh from './refresh/actionTypes'
Expand Down Expand Up @@ -43,6 +44,7 @@ export {
lockbox,
login,
manageAddresses,
onfido,
priceChart,
priceTicker,
refresh,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as layoutWallet from './layoutWallet/actions'
import * as lockbox from './lockbox/actions'
import * as login from './login/actions'
import * as manageAddresses from './manageAddresses/actions'
import * as onfido from './onfido/actions'
import * as priceChart from './priceChart/actions'
import * as priceTicker from './priceTicker/actions'
import * as refresh from './refresh/actions'
Expand Down Expand Up @@ -40,6 +41,7 @@ export {
identityVerification,
importBtcAddress,
manageAddresses,
onfido,
layoutWallet,
lockbox,
login,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const SYNC_ONFIDO = '@EVENT.SYNC_ONFIDO'
export const SYNC_ONFIDO_LOADING = '@ONFIDO.SYNC_ONFIDO_LOADING'
export const SYNC_ONFIDO_SUCCESS = '@ONFIDO.SYNC_ONFIDO_SUCCESS'
export const SYNC_ONFIDO_ERROR = '@ONFIDO.SYNC_ONFIDO_ERROR'
export const FETCH_ONFIDO_SDK_KEY = '@EVENT.FETCH_ONFIDO_SDK_KEY'
export const FETCH_ONFIDO_SDK_KEY_LOADING =
'@ONFIDO.FETCH_ONFIDO_SDK_KEY_LOADING'
export const FETCH_ONFIDO_SDK_KEY_SUCCESS =
'@ONFIDO.FETCH_ONFIDO_SDK_KEY_SUCCESS'
export const FETCH_ONFIDO_SDK_KEY_ERROR = '@ONFIDO.FETCH_ONFIDO_SDK_KEY_ERROR'
export const SET_ONFIDO_APPLICANT_ID = '@ONFIDO.SET_ONFIDO_APPLICANT_ID'
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as AT from './actionTypes'
export const syncOnfido = isSelfie => ({
type: AT.SYNC_ONFIDO,
payload: { isSelfie }
})
export const syncOnfidoLoading = () => ({ type: AT.SYNC_ONFIDO_LOADING })
export const syncOnfidoSuccess = () => ({ type: AT.SYNC_ONFIDO_SUCCESS })
export const syncOnfidoError = message => ({
type: AT.SYNC_ONFIDO_ERROR,
payload: { message }
})
export const fetchOnfidoSDKKey = () => ({ type: AT.FETCH_ONFIDO_SDK_KEY })
export const fetchOnfidoSDKKeyLoading = () => ({
type: AT.FETCH_ONFIDO_SDK_KEY_LOADING
})
export const fetchOnfidoSDKKeySuccess = onfidoSDKKey => ({
type: AT.FETCH_ONFIDO_SDK_KEY_SUCCESS,
payload: { onfidoSDKKey }
})
export const fetchOnfidoSDKKeyError = message => ({
type: AT.FETCH_ONFIDO_SDK_KEY_ERROR,
payload: { message }
})
export const setOnfidoApplicantId = applicantId => ({
type: AT.SET_ONFIDO_APPLICANT_ID,
payload: { applicantId }
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { assoc } from 'ramda'
import { Remote } from 'blockchain-wallet-v4/src'
import * as AT from './actionTypes'
export const INITIAL_STATE = {
onfidoSDKKey: Remote.NotAsked,
onfidoSyncStatus: Remote.NotAsked,
applicantId: ''
}
export default (state = INITIAL_STATE, action) => {
const { type, payload } = action
switch (type) {
case AT.FETCH_ONFIDO_SDK_KEY_ERROR: {
return assoc('onfidoSDKKey', Remote.Failure(payload.message), state)
}
case AT.FETCH_ONFIDO_SDK_KEY_LOADING: {
return assoc('onfidoSDKKey', Remote.Loading, state)
}
case AT.FETCH_ONFIDO_SDK_KEY_SUCCESS: {
return assoc('onfidoSDKKey', Remote.Success(payload.onfidoSDKKey), state)
}
case AT.SYNC_ONFIDO_ERROR: {
return assoc('onfidoSyncStatus', Remote.Failure(payload.message), state)
}
case AT.SYNC_ONFIDO_LOADING: {
return assoc('onfidoSyncStatus', Remote.Loading, state)
}
case AT.SYNC_ONFIDO_SUCCESS: {
return assoc('onfidoSyncStatus', Remote.Success(true), state)
}
case AT.SET_ONFIDO_APPLICANT_ID: {
return assoc('applicantId', payload.applicantId, state)
}
default:
return state
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { takeLatest } from 'redux-saga/effects'
import * as AT from './actionTypes'
import sagas from './sagas'
export default ({ api, coreSagas }) => {
const { syncOnfido, fetchOnfidoSDKKey } = sagas({ api, coreSagas })
return function*() {
yield takeLatest(AT.FETCH_ONFIDO_SDK_KEY, fetchOnfidoSDKKey)
yield takeLatest(AT.SYNC_ONFIDO, syncOnfido)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { put, call, select } from 'redux-saga/effects'
import { actions, model } from 'data'
import * as A from './actions'
import * as S from './selectors'
export const logLocation = 'components/identityVerification/sagas'
export default ({ api }) => {
const { COMPLETE } = model.analytics.KYC
const fetchOnfidoSDKKey = function*() {
try {
yield put(A.fetchOnfidoSDKKeyLoading())
const { token, applicantId } = yield call(api.fetchOnfidoSDKKey)
yield put(A.setOnfidoApplicantId(applicantId))
yield put(A.fetchOnfidoSDKKeySuccess(token))
} catch (error) {
yield put(A.fetchOnfidoSDKKeyError(error))
}
}
const syncOnfido = function*({ payload }) {
try {
const { isSelfie } = payload
const applicantId = yield select(S.getApplicantId)
yield put(A.syncOnfidoLoading())
yield call(api.syncOnfido, applicantId, isSelfie)
yield put(A.syncOnfidoSuccess())
yield put(actions.modules.profile.fetchUser())
yield put(actions.modals.closeAllModals())
yield put(actions.router.push('/exchange'))
yield put(actions.analytics.logKycEvent(COMPLETE))
} catch (error) {
yield put(A.syncOnfidoError(error))
}
}
return {
fetchOnfidoSDKKey,
syncOnfido
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { select } from 'redux-saga/effects'
import { expectSaga } from 'redux-saga-test-plan'
import { actions, model } from 'data'
import * as A from './actions'
import * as S from './selectors'
import sagas from './sagas'
const api = {
syncOnfido: jest.fn()
}
const { syncOnfido } = sagas({ api })
const { COMPLETE } = model.analytics.KYC
const isSelfie = true
const applicantId = '12312312asdAWeqwq23-21d13d3d2'
const action = {
payload: {
isSelfie
}
}
describe('syncOnfido', () => {
it('should sync with backend, redirect user to the exchange and log kyc complete event', () => {
return expectSaga(syncOnfido, action)
.provide([[select(S.getApplicantId), applicantId]])
.put(A.syncOnfidoLoading())
.call(api.syncOnfido, applicantId, isSelfie)
.put(A.syncOnfidoSuccess())
.put(actions.modules.profile.fetchUser())
.put(actions.modals.closeAllModals())
.put(actions.router.push('/exchange'))
.put(actions.analytics.logKycEvent(COMPLETE))
.run()
})
it('should save error state if sync fails', () => {
const error = {}
api.syncOnfido.mockRejectedValue(error)
return expectSaga(syncOnfido, action)
.provide([[select(S.getApplicantId), applicantId]])
.put(A.syncOnfidoLoading())
.call(api.syncOnfido, applicantId, isSelfie)
.put(A.syncOnfidoError(error))
.run()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { path } from 'ramda'
export const getApplicantId = path(['components', 'onfido', 'applicantId'])
export const getOnfidoSDKKey = path(['components', 'onfido', 'onfidoSDKKey'])
export const getOnfidoSyncStatus = path([
'components',
'onfido',
'onfidoSyncStatus'
])
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import lockbox from './lockbox/reducers'
import exchangeHistory from './exchangeHistory/reducers'
import layoutWallet from './layoutWallet/reducers'
import manageAddresses from './manageAddresses/reducers'
import onfido from './onfido/reducers'
import priceChart from './priceChart/reducers'
import sendBch from './sendBch/reducers'
import sendBtc from './sendBtc/reducers'
Expand All @@ -21,6 +22,7 @@ export default combineReducers({
layoutWallet,
lockbox,
manageAddresses,
onfido,
priceChart,
sendBch,
sendBtc,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import importBtcAddress from './importBtcAddress/sagaRegister'
import lockbox from './lockbox/sagaRegister'
import login from './login/sagaRegister'
import manageAddresses from './manageAddresses/sagaRegister'
import onfido from './onfido/sagaRegister'
import priceChart from './priceChart/sagaRegister'
import priceTicker from './priceTicker/sagaRegister'
import refresh from './refresh/sagaRegister'
Expand Down Expand Up @@ -43,6 +44,7 @@ export default ({ api, coreSagas, networks, options }) =>
yield fork(importBtcAddress({ api, coreSagas, networks }))
yield fork(login())
yield fork(manageAddresses({ api, networks }))
yield fork(onfido({ api, coreSagas }))
yield fork(priceChart({ coreSagas }))
yield fork(priceTicker({ coreSagas }))
yield fork(refresh())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import identityVerification from './identityVerification/sagas'
import importBtcAddress from './importBtcAddress/sagas'
import login from './login/sagas'
import manageAddresses from './manageAddresses/sagas'
import onfido from './onfido/sagas'
import priceChart from './priceChart/sagas'
import priceTicker from './priceTicker/sagas'
import refresh from './refresh/sagas'
Expand Down Expand Up @@ -39,6 +40,7 @@ export default ({ api, coreSagas, options, networks }) => ({
importBtcAddress: importBtcAddress({ api, coreSagas, networks }),
login: login(),
manageAddresses: manageAddresses({ api, networks }),
onfido: onfido({ api }),
priceChart: priceChart({ coreSagas }),
priceTicker: priceTicker({ coreSagas }),
refresh: refresh(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as exchangeHistory from './exchangeHistory/selectors'
import * as layoutWallet from './layoutWallet/selectors'
import * as lockbox from './lockbox/selectors'
import * as manageAddresses from './manageAddresses/selectors'
import * as onfido from './onfido/selectors'
import * as priceChart from './priceChart/selectors'
import * as priceTicker from './priceTicker/selectors'
import * as sendBch from './sendBch/selectors'
Expand All @@ -21,6 +22,7 @@ export {
layoutWallet,
lockbox,
manageAddresses,
onfido,
priceChart,
priceTicker,
sendBch,
Expand Down
103 changes: 103 additions & 0 deletions packages/blockchain-wallet-v4-frontend/src/modals/Onfido/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { bindActionCreators, compose } from 'redux'
import styled from 'styled-components'
import { pathEq, toLower } from 'ramda'
import { getData } from './selectors'
import { actions, model } from 'data'
import Loading from './template.loading'
import { Modal } from 'blockchain-info-components'
import { Remote } from 'blockchain-wallet-v4'
import DataError from 'components/DataError'
import modalEnhancer from 'providers/ModalEnhancer'
export const MODAL_NAME = 'Onfido'
export const { ONFIDO_STARTED } = model.analytics.KYC
const OnfidoIframe = styled.iframe.attrs({
allow: 'camera'
})`
width: 100%;
height: 604px;
border: none;
`
const OnfidoModal = styled(Modal)`
height: 604px;
display: flex;
${props => (props.onfidoActive ? `background-color: #f3f3f4;` : '')};
`
class OnfidoContainer extends React.PureComponent {
componentDidMount () {
this.props.actions.fetchOnfidoSDKKey()
this.props.analytics.logKycEvent(ONFIDO_STARTED)
window.addEventListener('message', this.handleOnfidoMessage, false)
}
componentWillUnmount () {
window.removeEventListener('message', this.handleOnfidoMessage)
}
handleOnfidoMessage = ({ data, origin }) => {
const { helperDomain, actions } = this.props
if (origin !== helperDomain) return
if (data.from !== 'onfido') return
if (data.to !== 'IdentityVerification') return
if (data.event !== 'done') return
const isSelfie = pathEq(['data', 'face', 'variant'], 'standard', data)
actions.syncOnfido(isSelfie)
}
render () {
const {
helperDomain,
position,
total,
onfidoSDKKey,
onfidoSyncStatus,
supportedDocuments,
actions
} = this.props
const docs = supportedDocuments.map(toLower).join('|')
return (
<OnfidoModal
size='medium'
position={position}
onfidoActive={Remote.Success.is(onfidoSDKKey)}
total={total}
>
{onfidoSDKKey.cata({
Success: sdkKey =>
onfidoSyncStatus.cata({
Success: () => <Loading />,
Loading: () => <Loading />,
NotAsked: () => (
<OnfidoIframe
src={`${helperDomain}/wallet-helper/onfido/#/token/${sdkKey}/docs/${docs}`}
sandbox='allow-same-origin allow-scripts'
scrolling='no'
id='onfido-iframe'
/>
),
Failure: () => <DataError onClick={actions.syncOnfido} />
}),
Loading: () => <Loading />,
Failure: () => <DataError onClick={actions.fetchOnfidoSDKKey} />,
NotAsked: () => <Loading />
})}
</OnfidoModal>
)
}
}
OnfidoContainer.propTypes = {
helperDomain: PropTypes.string.isRequired,
onfidoSDKKey: PropTypes.instanceOf(Remote).isRequired,
onfidoSyncStatus: PropTypes.instanceOf(Remote).isRequired
}
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(actions.components.onfido, dispatch),
analytics: bindActionCreators(actions.analytics, dispatch)
})
const enhance = compose(
modalEnhancer(MODAL_NAME),
connect(
getData,
mapDispatchToProps
)
)
export default enhance(OnfidoContainer)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { path } from 'ramda'
import { selectors } from 'data'
const { getOnfidoSDKKey, getOnfidoSyncStatus } = selectors.components.onfido
const { getSupportedDocuments } = selectors.components.identityVerification
export const getData = state => ({
onfidoSDKKey: getOnfidoSDKKey(state),
onfidoSyncStatus: getOnfidoSyncStatus(state),
supportedDocuments: getSupportedDocuments(state).getOrElse([
'PASSPORT',
'DRIVERS_LICENSE'
]),
helperDomain: path(
['walletOptionsPath', 'data', 'domains', 'walletHelper'],
state
)
})

0 comments on commit c1b7e31

Please sign in to comment.