UNPKG

@ajitpatel28/react-native-truecaller

Version:

Truecaller Integration with React Native for both Android[SDK v3.0.0] and IOS[SDK v0.1.8]

269 lines (248 loc) 8.12 kB
import { useState, useEffect, useCallback } from 'react'; import { Platform, NativeModules, NativeEventEmitter, DeviceEventEmitter, } from 'react-native'; import axios from 'axios'; import type { TruecallerConfig, TruecallerUserProfile, UseTruecallerResult, TruecallerAndroidResponse, TruecallerIOSResponse, } from '../interfaces'; import { TRUECALLER_ANDROID_EVENTS, TRUECALLER_IOS_EVENTS, TRUECALLER_API_URLS, DEFAULT_BUTTON_TEXT_COLOR, DEFAULT_BUTTON_COLOR, DEFAULT_BUTTON_SHAPE, DEFAULT_BUTTON_TEXT, DEFAULT_CONSENT_HEADING, DEFAULT_FOOTER_BUTTON_TEXT, } from '../constants'; const TruecallerAndroidModule = NativeModules.TruecallerModule; const TruecallerIOS = NativeModules.ReactNativeTruecaller; export const useTruecaller = ( config: TruecallerConfig ): UseTruecallerResult => { const [userProfile, setUserProfile] = useState<TruecallerUserProfile | null>( null ); const [error, setError] = useState<string | null>(null); const [isTruecallerInitialized, setIsTruecallerInitialized] = useState(false); const initializeTruecallerSDK = useCallback(async () => { try { if (Platform.OS === 'android' && !config.androidClientId) { throw new Error('Android client ID is required for Android platform'); } if (Platform.OS === 'ios' && (!config.iosAppKey || !config.iosAppLink)) { throw new Error( 'iOS app key and app link are required for iOS platform' ); } if (Platform.OS === 'android') { const androidConfig = { buttonColor: config.androidButtonColor || DEFAULT_BUTTON_COLOR, buttonTextColor: config.androidButtonTextColor || DEFAULT_BUTTON_TEXT_COLOR, buttonText: config.androidButtonText || DEFAULT_BUTTON_TEXT, buttonShape: config.androidButtonShape || DEFAULT_BUTTON_SHAPE, footerButtonText: config.androidFooterButtonText || DEFAULT_FOOTER_BUTTON_TEXT, consentHeading: config.androidConsentHeading || DEFAULT_CONSENT_HEADING, }; await TruecallerAndroidModule.initializeSdk(androidConfig); } else { await TruecallerIOS.initializeSdk(config); } setIsTruecallerInitialized(true); setError(null); } catch (err) { setError((err as Error).message); setIsTruecallerInitialized(false); } }, [config]); useEffect(() => { let successListener: any; let failureListener: any; if (isTruecallerInitialized) { if (Platform.OS === 'android') { if (!config.androidClientId) { setError('Android client ID is required for Android platform'); return; } successListener = DeviceEventEmitter.addListener( TRUECALLER_ANDROID_EVENTS.SUCCESS, (data: TruecallerAndroidResponse) => { // custom handler if provided, otherwise default handler if (config.androidSuccessHandler) { config.androidSuccessHandler(data); } else { handleAuthorizationSuccess(data); } } ); failureListener = DeviceEventEmitter.addListener( TRUECALLER_ANDROID_EVENTS.FAILURE, (err: { errorMessage: string }) => { setError(err.errorMessage); setUserProfile(null); } ); } else if (Platform.OS === 'ios') { if (!config.iosAppKey || !config.iosAppLink) { setError('iOS app key and app link are required for iOS platform'); return; } const eventEmitter = new NativeEventEmitter(TruecallerIOS); successListener = eventEmitter.addListener( TRUECALLER_IOS_EVENTS.SUCCESS, handleAuthorizationSuccess ); failureListener = eventEmitter.addListener( TRUECALLER_IOS_EVENTS.FAILURE, (err: { errorMessage: string }) => { setError(err.errorMessage); setUserProfile(null); } ); } } return () => { if (successListener) { if (Platform.OS === 'android') { successListener.remove(); } else { successListener.remove(); } } if (failureListener) { if (Platform.OS === 'android') { failureListener.remove(); } else { failureListener.remove(); } } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [isTruecallerInitialized, config]); const handleAuthorizationSuccess = async ( data: TruecallerAndroidResponse | TruecallerIOSResponse ) => { try { if (Platform.OS === 'android') { const { authorizationCode, codeVerifier } = data as TruecallerAndroidResponse; const accessToken = await exchangeAuthorizationCodeForAccessToken( authorizationCode, codeVerifier ); const userInfo = await fetchUserProfile(accessToken); setUserProfile(userInfo); } else { // For iOS, the profile data is directly available setUserProfile( mapIOSResponseToUserProfile(data as TruecallerIOSResponse) ); } setError(null); } catch (err) { setError((err as Error).message); setUserProfile(null); } }; const exchangeAuthorizationCodeForAccessToken = async ( authorizationCode: string, codeVerifier: string ): Promise<string> => { const clientId = config.androidClientId; const response = await axios.post( TRUECALLER_API_URLS.TOKEN_URL, { grant_type: 'authorization_code', client_id: clientId, code: authorizationCode, code_verifier: codeVerifier, }, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, } ); return response.data.access_token; }; const fetchUserProfile = async ( accessToken: string ): Promise<TruecallerUserProfile> => { const response = await axios.get(TRUECALLER_API_URLS.USER_INFO_URL, { headers: { Authorization: `Bearer ${accessToken}` }, }); return mapAndroidResponseToUserProfile(response.data); }; const mapAndroidResponseToUserProfile = ( data: TruecallerAndroidResponse ): TruecallerUserProfile => ({ firstName: data.given_name, lastName: data.family_name, email: data.email, countryCode: data.phone_number_country_code, gender: data.gender, phoneNumber: data.phone_number, }); const mapIOSResponseToUserProfile = ( data: TruecallerIOSResponse ): TruecallerUserProfile => ({ firstName: data.firstName, lastName: data.lastName, email: data.email, countryCode: data.countryCode, gender: data.gender, phoneNumber: data.phoneNumber, }) as TruecallerUserProfile; const isSdkUsable = () => { if (Platform.OS === 'android') return TruecallerAndroidModule.isSdkUsable(); else if (Platform.OS === 'ios') return TruecallerIOS.isSupported(); return false; }; const openTruecallerForVerification = useCallback(async () => { if (!isTruecallerInitialized) { setError('SDK is not initialized. Call initializeSDK first.'); return; } try { if (!isSdkUsable()) { throw new Error('Truecaller SDK is not usable on this device'); } if (Platform.OS === 'android') { if (!config.androidClientId) { throw new Error('Android client ID is required for Android platform'); } await TruecallerAndroidModule.requestAuthorizationCode(); } else { if (!config.iosAppKey || !config.iosAppLink) { throw new Error( 'iOS app key and app link are required for iOS platform' ); } await TruecallerIOS.requestTrueProfile(); } } catch (err) { setError((err as Error).message); } }, [isTruecallerInitialized, config]); return { userProfile, error, isTruecallerInitialized, initializeTruecallerSDK, isSdkUsable, openTruecallerForVerification, }; };