UNPKG

react-native-dojah-sdks

Version:

> https://github.com/dojah-inc/React-native-SDK

463 lines (431 loc) 14.1 kB
import React, {useState, useEffect, useCallback, useMemo} from 'react'; import PropTypes from 'prop-types'; import { ActivityIndicator, Platform, View, Text, StyleSheet, } from 'react-native'; import {WebView} from 'react-native-webview'; import { checkMultiple, requestMultiple, openSettings, PERMISSIONS, RESULTS, } from 'react-native-permissions'; import Geolocation from 'react-native-geolocation-service'; import AsyncStorage from '@react-native-async-storage/async-storage'; /** * @param {String} appID Your dojah application ID, go to your dashboard at https://app.dojah.io/dashboard to retrieve it * @param {String} publicKey Your dojah public key, go to your dashboard at https://app.dojah.io/dashboard to retrieve it * @param {String} type The dojah widget type to load, go to your dashboard at https://app.dojah.io/dashboard to configure it * @param {func} response callback called when a message is available: * first parameter is type of message: one of loading, begin, success, error, and close * second paramater is the data, * @param {Object} config These are the configuration options available to you possible options are: * {debug: BOOL, otp: BOOL, selfie: BOOL} * NOTE: The otp and selfie options are only * available to the `verification` widget * @param {Object} userData Pass in the user's data in the following keys: `first_name` for the first name, * `last_name` for the last name and `dob` for the date of birth * @param {Object} metadata Pass in any data you choose to tag the response when passed to you, this will be * returned to you in the `kyc_widget` webhook or passed as a parameter to the onSuccess function * @param {Object} govData Pass in the following keys: `nin` for the National Identification Number, * `bvn`, 'mobile', 'dl'. * @param {StyleProp} outerContainerStyle The style of the outermost view * @param {StyleProp} outerContainerStyle The style of the outermost view * @param {StyleProp} style The style of the middle view * @param {StyleProp} innerContainerStyle The style of the innermost view */ const PLATFORM_CAMERA = Platform.OS === 'android' ? PERMISSIONS.ANDROID.CAMERA : PERMISSIONS.IOS.CAMERA; const PLATFORM_LOCATION = Platform.OS === 'android' ? [ PERMISSIONS.ANDROID.ACCESS_BACKGROUND_LOCATION, PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION, ] : PERMISSIONS.IOS.LOCATION_ALWAYS; const Dojah = ({ appID, publicKey, type, response, config, userData, govData, metadata, outerContainerStyle, style, innerContainerStyle, }) => { const {uri, defaultStyle, injectJavaScript} = Dojah.config; // State is undefined for not respoded, // null for never requested, true for approved and false for denied const [granted, setGranted] = useState({ location: undefined, camera: undefined, }); const [location, setLocation] = useState(''); const needsCamera = true; const needsLocation = true; const permissionsNeeded = useMemo(() => needsCamera || needsLocation, [ needsCamera, needsLocation, ]); useEffect(() => { if (permissionsNeeded) { requestPermission(); } return () => response('close'); }, [ permissionsNeeded, requestPermission, type, needsCamera, needsLocation, response, ]); const getCurrentPosition = useCallback(() => { Geolocation.getCurrentPosition( async (loc) => { log('GeoLocation:', loc); setLocation({ ...loc, }); }, (error) => { log('GeoLocation Error:', error); setGranted((state) => ({...state, location: false})); }, { distanceFilter: 10, maximumAge: 0, timeout: 6 * 60 * 60 * 1000, enableHighAccuracy: true, showLocationDialog: true, forceRequestLocation: true, forceLocationManager: false, showsBackgroundLocationIndicator: false, }, ); }, [log]); const requestPermission = useCallback(() => { const permissions = [ needsCamera ? PLATFORM_CAMERA : null, needsLocation ? PLATFORM_LOCATION : null, ] .filter((perm) => !!perm) .flatMap((item) => item); checkMultiple(permissions) .then((statuses) => { let request = false; let read = false; permissions.every((permission) => { const check = permission === PLATFORM_CAMERA ? 'camera' : 'location'; switch (statuses[permission]) { case RESULTS.GRANTED: log('The permission is granted', permission); setGranted((state) => ({...state, [check]: true})); if (permission === PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION) { read = true; } break; case RESULTS.UNAVAILABLE: log( 'This feature is not available (on this device / in this context)', permission, ); // If it's background location don't return false if ( permission === PERMISSIONS.ANDROID.ACCESS_BACKGROUND_LOCATION ) { return true; } setGranted((state) => ({...state, [check]: false})); return false; case RESULTS.BLOCKED: log('The permission is denied and not requestable anymore'); setGranted((state) => ({...state, [check]: false})); openSettings().catch(() => log('We cannot open settings')); return false; case RESULTS.DENIED: log( 'The permission has not been requested / is denied but requestable', ); request = true; break; case RESULTS.LIMITED: log('The permission is limited: some actions are possible'); request = true; break; default: log('The permission is unknown', statuses, permission); break; } return true; }); if (request) { makeRequest(permissions); } else if (read) { getCurrentPosition(); } }) .catch((e) => { log('Error when checking for permissions', e); }); }, [getCurrentPosition, log, makeRequest, needsCamera, needsLocation]); const makeRequest = useCallback( (permissions) => { log('Dojah Requesting:', permissions); requestMultiple(permissions).then((statuses) => { log('ANDROID Camera', statuses[PERMISSIONS.ANDROID.CAMERA]); log('IOS Camera', statuses[PERMISSIONS.IOS.CAMERA]); log( 'ANDROID Background Location', statuses[PERMISSIONS.ANDROID.ACCESS_BACKGROUND_LOCATION], ); log( 'ANDROID Fine Location', statuses[PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION], ); log('IOS Location', statuses[PERMISSIONS.LOCATION_ALWAYS]); const _location = statuses[PERMISSIONS.ANDROID.ACCESS_BACKGROUND_LOCATION] === 'granted' || statuses[PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION] === 'granted' || statuses[PERMISSIONS.LOCATION_ALWAYS] === 'granted'; setGranted({ camera: statuses[PERMISSIONS.ANDROID.CAMERA] === 'granted' || statuses[PERMISSIONS.IOS.CAMERA] === 'granted' || null, location: _location || null, }); if (_location) { getCurrentPosition(); } }); }, [log, getCurrentPosition], ); if (permissionsNeeded) { if ( (needsLocation && granted.location === undefined) || (needsCamera && granted.camera === undefined) ) { return ( <View style={styles.center}> <ActivityIndicator size="large" color="#3977de" /> </View> ); } if ( (needsLocation && !granted.location) || (needsCamera && !granted.camera) ) { return ( <View style={styles.center}> <Text style={styles.text}> You need to grant all necessary permissions. You denied the the following permissions:{' '} {Object.keys(granted) .map((permission) => (!granted[permission] ? permission : null)) .filter((permission) => !!permission) .join(', ')} </Text> </View> ); } } return ( <View style={[defaultStyle, outerContainerStyle]}> <WebView originWhiteList={['*']} source={{ baseUrl: 'https://widget.dojah.io', html: ` <html> <head> <script type="application/javascript" src="${uri}"></script> <meta name="viewport" content="width=device-width"> </head> <body></body> </html> `, }} style={style} containerStyle={innerContainerStyle} onMessage={async (e) => { const data = JSON.parse(e.nativeEvent.data); if (data.type === 'success') { const widgetData = data.data.data; await AsyncStorage.setItem( '@Dojah:SESSION_ID', `${data.data.verificationId}`, ); try { if (widgetData.address) { const addressLocation = widgetData.address.data.location.addressLocation; await AsyncStorage.setItem( '@Dojah:LATITUDE', addressLocation.latitude, ); await AsyncStorage.setItem( '@Dojah:LONGITUDE', addressLocation.longitude, ); } } catch {} } response(data.type, data); }} injectedJavaScript={injectJavaScript( appID, publicKey, type, config, userData, govData, metadata, location, )} decelerationRate={'normal'} cacheEnabled={false} cacheMode={'LOAD_NO_CACHE'} bounces={false} injectedJavaScriptBeforeContentLoadedForMainFrameOnly={true} javaScriptEnabled={true} scalesPageToFit={Platform.OS === 'android'} mediaPlaybackRequiresUserAction={false} useWebkit={true} startInLoadingState={true} androidLayerType="hardware" allowsInlineMediaPlayback={true} allowsFullscreenVideo={false} geolocationEnabled={true} /> </View> ); }; Dojah.hydrate = (appId, pKey) => { Geolocation.watchPosition( async (loc) => { const session = await AsyncStorage.getItem('@Dojah:SESSION_ID'); if (!session) { return; } const addressLocation = { latitude: await AsyncStorage.getItem('@Dojah:LATITUDE'), longitude: await AsyncStorage.getItem('@Dojah:LONGITUDE'), }; const userLocation = { ...loc, latitude: loc.coords.latitude, longitude: loc.coords.longitude, }; // Submit the position await fetch('https://kyc.dojah.io/address', { method: 'POST', body: JSON.stringify({ location: userLocation, baseLocation: addressLocation, background: true, appId, pKey, session, }), headers: { 'Content-Type': 'application/json', }, }); }, (e) => { console.warn('Hydration Failed', e); }, { distanceFilter: 10, maximumAge: 0, timeout: 6 * 60 * 60 * 1000, enableHighAccuracy: true, showLocationDialog: true, forceRequestLocation: true, forceLocationManager: false, showsBackgroundLocationIndicator: false, }, ); }; Dojah.config = { uri: 'https://widget.dojah.io/widget.js', defaultStyle: { width: '100%', height: '100%', backgroundColor: 'red', }, injectJavaScript: function ( appID, publicKey, type, config, userData, govData, metadata, location, ) { return ` const options = { app_id: "${appID}", p_key: "${publicKey}", type: "${type}", config: ${config ? JSON.stringify(config) : null}, user_data: ${userData ? JSON.stringify(userData) : null}, gov_data: ${govData ? JSON.stringify(govData) : null}, metadata: ${metadata ? JSON.stringify(metadata) : null}, __location: ${location ? JSON.stringify(location) : null}, onSuccess: function (response) { window.ReactNativeWebView.postMessage(JSON.stringify({type: 'success', data: response})); }, onError: function (err) { window.ReactNativeWebView.postMessage(JSON.stringify({type: 'error', data: err})); }, onClose: function (err) { window.ReactNativeWebView.postMessage(JSON.stringify({type: 'close', data: err})); } }; const connect = new window.Connect(options); connect.setup(); connect.open(); window.ReactNativeWebView.postMessage(JSON.stringify({type: 'loading'})); document.getElementsByTagName('iframe')[0].onload = function() { window.ReactNativeWebView.postMessage(JSON.stringify({type: 'begin'})); }; true; `; }, }; const styles = StyleSheet.create({ center: { justifyContent: 'center', alignItems: 'center', alignSelf: 'center', width: '80%', height: '80%', }, text: { color: 'black', textAlign: 'center', fontSize: 13, }, }); Dojah.propTypes = { appID: PropTypes.string.isRequired, publicKey: PropTypes.string.isRequired, type: PropTypes.string.isRequired, response: PropTypes.func.isRequired, }; export default Dojah;