Skip to content

Commit

Permalink
Merge pull request #31378 from VickyStash/ts-migration/onfido-component
Browse files Browse the repository at this point in the history
[TS migration] Migrate 'Onfido' component to TypeScript
  • Loading branch information
bondydaa committed Mar 15, 2024
2 parents 62b1b35 + b1d36a8 commit 8b54aff
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 71 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
import lodashGet from 'lodash/get';
import {Onfido as OnfidoSDK} from 'onfido-sdk-ui';
import React, {forwardRef, useEffect} from 'react';
import _ from 'underscore';
import type {ForwardedRef} from 'react';
import type {LocaleContextProps} from '@components/LocaleContextProvider';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import Log from '@libs/Log';
import type {ThemeColors} from '@styles/theme/types';
import FontUtils from '@styles/utils/FontUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import './index.css';
import onfidoPropTypes from './onfidoPropTypes';
import type {OnfidoElement, OnfidoProps} from './types';

function initializeOnfido({sdkToken, onSuccess, onError, onUserExit, preferredLocale, translate, theme}) {
type InitializeOnfidoProps = OnfidoProps &
Pick<LocaleContextProps, 'translate' | 'preferredLocale'> & {
theme: ThemeColors;
};

type OnfidoEvent = Event & {
detail?: Record<string, unknown>;
};

function initializeOnfido({sdkToken, onSuccess, onError, onUserExit, preferredLocale, translate, theme}: InitializeOnfidoProps) {
OnfidoSDK.init({
token: sdkToken,
containerId: CONST.ONFIDO.CONTAINER_ID,
Expand All @@ -20,7 +31,7 @@ function initializeOnfido({sdkToken, onSuccess, onError, onUserExit, preferredLo
fontFamilySubtitle: `${FontUtils.fontFamily.platform.EXP_NEUE}, -apple-system, serif`,
fontFamilyBody: `${FontUtils.fontFamily.platform.EXP_NEUE}, -apple-system, serif`,
fontSizeTitle: `${variables.fontSizeLarge}px`,
fontWeightTitle: FontUtils.fontWeight.bold,
fontWeightTitle: Number(FontUtils.fontWeight.bold),
fontWeightSubtitle: 400,
fontSizeSubtitle: `${variables.fontSizeNormal}px`,
colorContentTitle: theme.text,
Expand All @@ -45,10 +56,10 @@ function initializeOnfido({sdkToken, onSuccess, onError, onUserExit, preferredLo
colorBorderLinkUnderline: theme.link,
colorBackgroundLinkHover: theme.link,
colorBackgroundLinkActive: theme.link,
authAccentColor: theme.link,
colorBackgroundInfoPill: theme.link,
colorBackgroundSelector: theme.appBG,
colorBackgroundDocTypeButton: theme.success,
borderWidthSurfaceModal: '0px',
colorBackgroundDocTypeButtonHover: theme.successHover,
colorBackgroundButtonIconHover: theme.transparent,
colorBackgroundButtonIconActive: theme.transparent,
Expand All @@ -57,11 +68,10 @@ function initializeOnfido({sdkToken, onSuccess, onError, onUserExit, preferredLo
{
type: CONST.ONFIDO.TYPE.DOCUMENT,
options: {
useLiveDocumentCapture: true,
forceCrossDevice: true,
hideCountrySelection: true,
country: 'USA',
documentTypes: {
// eslint-disable-next-line @typescript-eslint/naming-convention
driving_licence: {
country: 'USA',
},
Expand All @@ -76,17 +86,15 @@ function initializeOnfido({sdkToken, onSuccess, onError, onUserExit, preferredLo
},
},
],
smsNumberCountryCode: CONST.ONFIDO.SMS_NUMBER_COUNTRY_CODE.US,
showCountrySelection: false,
onComplete: (data) => {
if (_.isEmpty(data)) {
if (isEmptyObject(data)) {
Log.warn('Onfido completed with no data');
}
onSuccess(data);
},
onError: (error) => {
const errorType = lodashGet(error, 'type');
const errorMessage = lodashGet(error, 'message', CONST.ERROR.UNKNOWN_ERROR);
const errorType = error.type;
const errorMessage = error.message ?? CONST.ERROR.UNKNOWN_ERROR;
Log.hmmm('Onfido error', {errorType, errorMessage});
if (errorType === CONST.WALLET.ERROR.ONFIDO_USER_CONSENT_DENIED) {
onUserExit();
Expand All @@ -103,26 +111,27 @@ function initializeOnfido({sdkToken, onSuccess, onError, onUserExit, preferredLo
// https://github.com/Expensify/App/issues/17244
// https://documentation.onfido.com/sdk/web/#custom-languages
phrases: {
// eslint-disable-next-line @typescript-eslint/naming-convention
'generic.back': translate('common.back'),
},
},
});
}

function logOnFidoEvent(event) {
function logOnFidoEvent(event: OnfidoEvent) {
Log.hmmm('Receiving Onfido analytic event', event.detail);
}

const Onfido = forwardRef((props, ref) => {
function Onfido({sdkToken, onSuccess, onError, onUserExit}: OnfidoProps, ref: ForwardedRef<OnfidoElement>) {
const {preferredLocale, translate} = useLocalize();
const theme = useTheme();

useEffect(() => {
initializeOnfido({
sdkToken: props.sdkToken,
onSuccess: props.onSuccess,
onError: props.onError,
onUserExit: props.onUserExit,
sdkToken,
onSuccess,
onError,
onUserExit,
preferredLocale,
translate,
theme,
Expand All @@ -140,8 +149,8 @@ const Onfido = forwardRef((props, ref) => {
ref={ref}
/>
);
});
}

Onfido.displayName = 'Onfido';
Onfido.propTypes = onfidoPropTypes;
export default Onfido;

export default forwardRef(Onfido);
11 changes: 0 additions & 11 deletions src/components/Onfido/index.desktop.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import {OnfidoCaptureType, OnfidoCountryCode, OnfidoDocumentType, Onfido as OnfidoSDK} from '@onfido/react-native-sdk';
import lodashGet from 'lodash/get';
import {OnfidoCaptureType, OnfidoCountryCode, OnfidoDocumentType, Onfido as OnfidoSDK, OnfidoTheme} from '@onfido/react-native-sdk';
import React, {useEffect} from 'react';
import {Alert, Linking} from 'react-native';
import {checkMultiple, PERMISSIONS, RESULTS} from 'react-native-permissions';
import _ from 'underscore';
import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import useLocalize from '@hooks/useLocalize';
import getPlatform from '@libs/getPlatform';
import Log from '@libs/Log';
import CONST from '@src/CONST';
import onfidoPropTypes from './onfidoPropTypes';
import type {TranslationPaths} from '@src/languages/types';
import type {OnfidoProps} from './types';

function Onfido({sdkToken, onUserExit, onSuccess, onError}) {
function Onfido({sdkToken, onUserExit, onSuccess, onError}: OnfidoProps) {
const {translate} = useLocalize();

useEffect(() => {
OnfidoSDK.start({
sdkToken,
theme: OnfidoTheme.AUTOMATIC,
flowSteps: {
welcome: true,
captureFace: {
Expand All @@ -30,24 +30,25 @@ function Onfido({sdkToken, onUserExit, onSuccess, onError}) {
})
.then(onSuccess)
.catch((error) => {
const errorMessage = lodashGet(error, 'message', CONST.ERROR.UNKNOWN_ERROR);
const errorType = lodashGet(error, 'type');
const errorMessage = error.message ?? CONST.ERROR.UNKNOWN_ERROR;
const errorType = error.type;

Log.hmmm('Onfido error on native', {errorType, errorMessage});

// If the user cancels the Onfido flow we won't log this error as it's normal. In the React Native SDK the user exiting the flow will trigger this error which we can use as
// our "user exited the flow" callback. On web, this event has it's own callback passed as a config so we don't need to bother with this there.
if (_.contains([CONST.ONFIDO.ERROR.USER_CANCELLED, CONST.ONFIDO.ERROR.USER_TAPPED_BACK, CONST.ONFIDO.ERROR.USER_EXITED], errorMessage)) {
if ([CONST.ONFIDO.ERROR.USER_CANCELLED, CONST.ONFIDO.ERROR.USER_TAPPED_BACK, CONST.ONFIDO.ERROR.USER_EXITED].includes(errorMessage)) {
onUserExit();
return;
}

if (!_.isEmpty(errorMessage) && getPlatform() === CONST.PLATFORM.IOS) {
if (!!errorMessage && getPlatform() === CONST.PLATFORM.IOS) {
checkMultiple([PERMISSIONS.IOS.MICROPHONE, PERMISSIONS.IOS.CAMERA])
.then((statuses) => {
const isMicAllowed = statuses[PERMISSIONS.IOS.MICROPHONE] === RESULTS.GRANTED;
const isCameraAllowed = statuses[PERMISSIONS.IOS.CAMERA] === RESULTS.GRANTED;
let alertTitle = '';
let alertMessage = '';
let alertTitle: TranslationPaths | '' = '';
let alertMessage: TranslationPaths | '' = '';
if (!isCameraAllowed) {
alertTitle = 'onfidoStep.cameraPermissionsNotGranted';
alertMessage = 'onfidoStep.cameraRequestMessage';
Expand All @@ -56,7 +57,7 @@ function Onfido({sdkToken, onUserExit, onSuccess, onError}) {
alertMessage = 'onfidoStep.microphoneRequestMessage';
}

if (!_.isEmpty(alertTitle) && !_.isEmpty(alertMessage)) {
if (!!alertTitle && !!alertMessage) {
Alert.alert(
translate(alertTitle),
translate(alertMessage),
Expand Down Expand Up @@ -93,7 +94,6 @@ function Onfido({sdkToken, onUserExit, onSuccess, onError}) {
return <FullscreenLoadingIndicator />;
}

Onfido.propTypes = onfidoPropTypes;
Onfido.displayName = 'Onfido';

export default Onfido;
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import lodashGet from 'lodash/get';
import React, {useEffect, useRef} from 'react';
import BaseOnfidoWeb from './BaseOnfidoWeb';
import onfidoPropTypes from './onfidoPropTypes';
import type {OnfidoElement, OnfidoProps} from './types';

function Onfido({sdkToken, onSuccess, onError, onUserExit}) {
const baseOnfidoRef = useRef(null);
function Onfido({sdkToken, onSuccess, onError, onUserExit}: OnfidoProps) {
const baseOnfidoRef = useRef<OnfidoElement>(null);

useEffect(
() => () => {
const onfidoOut = lodashGet(baseOnfidoRef.current, 'onfidoOut');
const onfidoOut = baseOnfidoRef.current?.onfidoOut;

if (!onfidoOut) {
return;
}
Expand All @@ -29,7 +29,6 @@ function Onfido({sdkToken, onSuccess, onError, onUserExit}) {
);
}

Onfido.propTypes = onfidoPropTypes;
Onfido.displayName = 'Onfido';

export default Onfido;
15 changes: 0 additions & 15 deletions src/components/Onfido/onfidoPropTypes.js

This file was deleted.

28 changes: 28 additions & 0 deletions src/components/Onfido/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type {OnfidoResult} from '@onfido/react-native-sdk';
import type {Handle} from 'onfido-sdk-ui/types/Onfido';
import type {CompleteData} from 'onfido-sdk-ui/types/Types';
import type {OnyxEntry} from 'react-native-onyx';

type OnfidoData = CompleteData | OnfidoResult;

type OnfidoDataWithApplicantID = OnfidoData & {
applicantID: OnyxEntry<string>;
};

type OnfidoElement = HTMLDivElement & {onfidoOut?: Handle};

type OnfidoProps = {
/** Token used to initialize the Onfido SDK */
sdkToken: string;

/** Called when the user intentionally exits the flow without completing it */
onUserExit: () => void;

/** Called when the user is totally done with Onfido */
onSuccess: (data: OnfidoData) => void;

/** Called when Onfido throws an error */
onError: (error?: string) => void;
};

export type {OnfidoProps, OnfidoElement, OnfidoData, OnfidoDataWithApplicantID};
3 changes: 2 additions & 1 deletion src/libs/actions/BankAccounts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Onyx from 'react-native-onyx';
import type {OnfidoDataWithApplicantID} from '@components/Onfido/types';
import * as API from '@libs/API';
import type {
AddPersonalBankAccountParams,
Expand Down Expand Up @@ -435,7 +436,7 @@ function connectBankAccountManually(bankAccountID: number, bankAccount: PlaidBan
/**
* Verify the user's identity via Onfido
*/
function verifyIdentityForBankAccount(bankAccountID: number, onfidoData: Record<string, unknown>, policyID: string) {
function verifyIdentityForBankAccount(bankAccountID: number, onfidoData: OnfidoDataWithApplicantID, policyID: string) {
const parameters: VerifyIdentityForBankAccountParams = {
bankAccountID,
onfidoData: JSON.stringify(onfidoData),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {withOnyx} from 'react-native-onyx';
import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import InteractiveStepSubHeader from '@components/InteractiveStepSubHeader';
// @ts-expect-error TODO: Remove this once Onfido (https://github.com/Expensify/App/issues/25136) is migrated to TypeScript.
import Onfido from '@components/Onfido';
import type {OnfidoData} from '@components/Onfido/types';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
import useLocalize from '@hooks/useLocalize';
Expand Down Expand Up @@ -41,7 +41,7 @@ function VerifyIdentity({reimbursementAccount, onBackButtonPress, onfidoApplican

const policyID = reimbursementAccount?.achData?.policyID ?? '';
const handleOnfidoSuccess = useCallback(
(onfidoData: Record<string, unknown>) => {
(onfidoData: OnfidoData) => {
BankAccounts.verifyIdentityForBankAccount(Number(reimbursementAccount?.achData?.bankAccountID ?? '0'), {...onfidoData, applicantID: onfidoApplicantID}, policyID);
BankAccounts.updateReimbursementAccountDraft({isOnfidoSetupComplete: true});
},
Expand Down Expand Up @@ -75,7 +75,7 @@ function VerifyIdentity({reimbursementAccount, onBackButtonPress, onfidoApplican
<FullPageOfflineBlockingView>
<ScrollView contentContainerStyle={styles.flex1}>
<Onfido
sdkToken={onfidoToken}
sdkToken={onfidoToken ?? ''}
onUserExit={handleOnfidoUserExit}
onError={handleOnfidoError}
onSuccess={handleOnfidoSuccess}
Expand Down

0 comments on commit 8b54aff

Please sign in to comment.