import { NativeEventEmitter } from 'react-native'; import type { UNVeryfiCredentials } from '../types/shared/veryfi.types'; // eslint-disable-next-line @typescript-eslint/no-explicit-any let VeryfiLens: any = null; try { // eslint-disable-next-line @typescript-eslint/no-var-requires VeryfiLens = require('@veryfi/react-native-veryfi-lens').default; } catch { // Veryfi SDK not installed β€” will use web fallback } export const isVeryfiAvailable = (): boolean => { return VeryfiLens != null; }; export interface UNVeryfiImage { base64Img: string; isFront: boolean; } const CHECK_SETTINGS = { documentTypes: ['check'], checksBackIsOn: true, blurDetectionIsOn: true, autoDocDetectionAndCropIsOn: true, dataExtractionEngine: true, returnStitchedPDF: true, originalImageMaxSizeInMB: 1.4, }; // Veryfi's default English back-capture modal string; overridden to append the endorsement. const BACK_CAPTURE_MODAL_KEY = 'Capture the back side of the check?'; const buildEndorsement = (bankName?: string): string => { const bank = bankName?.trim(); // Bank-agnostic fallback when the bank name is absent, so the copy never reads "...deposit at ". return `Please make sure to sign the back and write β€œFor mobile deposit ${bank ? `at ${bank}` : 'only'}”`; }; export const configureAndShowVeryfiCamera = ( credentials: UNVeryfiCredentials, bankName: string | undefined, onImages: (images: UNVeryfiImage[]) => void, onError: (error: string) => void ): void => { if (!VeryfiLens) { onError('Veryfi SDK is not available'); return; } const emitter = new NativeEventEmitter(VeryfiLens.NativeModule); // eslint-disable-next-line @typescript-eslint/no-explicit-any const subscriptions: any[] = []; let delivered = false; const cleanup = () => { subscriptions.forEach((sub) => sub.remove()); }; const deliverImages = (imagePaths: string[]) => { if (delivered) return; delivered = true; let converted = 0; const images: UNVeryfiImage[] = []; imagePaths.forEach((filePath, index) => { VeryfiLens.getFileBase64( filePath, // errorCallback () => { converted++; if (converted === imagePaths.length) { cleanup(); if (images.length > 0) { onImages(images); } else { onError('Failed to convert check images'); } } }, // successCallback (base64Data: string) => { images.push({ base64Img: base64Data, isFront: index === 1, }); converted++; if (converted === imagePaths.length) { cleanup(); onImages(images); } } ); }); }; // Process images when stitched PDF is ready (matches Android pattern) subscriptions.push( // eslint-disable-next-line @typescript-eslint/no-explicit-any emitter.addListener(VeryfiLens.Events.onVeryfiLensUpdate, (event: any) => { if (event.status === 'inprogress' && event.msg === 'img_stitched_pdf_path') { const paths = event.img_original_paths || []; if (paths.length > 0) { deliverImages(paths); } } }) ); // No onClose listener β€” if the user cancels, we simply don't dispatch // unitVeryfiResponse, and the web SDK's polling handles the timeout. subscriptions.push( // eslint-disable-next-line @typescript-eslint/no-explicit-any emitter.addListener(VeryfiLens.Events.onVeryfiLensError, (event: any) => { cleanup(); onError(event.msg || 'Veryfi error'); }) ); const veryfiCredentials = { clientId: credentials.clientId, userName: credentials.userName, apiKey: credentials.apiKey, url: credentials.url, }; const endorsement = buildEndorsement(bankName); const settings = { ...CHECK_SETTINGS, customLensStrings: { en: { [BACK_CAPTURE_MODAL_KEY]: `${BACK_CAPTURE_MODAL_KEY}\n\n${endorsement}`, }, }, }; VeryfiLens.configureWithCredentials(veryfiCredentials, settings, () => { VeryfiLens.showCamera(); }); };