@ajitpatel28/react-native-truecaller
Version:
Truecaller Integration with React Native for both Android[SDK v3.0.0] and IOS[SDK v0.1.8]
188 lines (187 loc) • 7.08 kB
JavaScript
;
import { useState, useEffect, useCallback } from 'react';
import { Platform, NativeModules, NativeEventEmitter, DeviceEventEmitter } from 'react-native';
import axios from 'axios';
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.js";
const TruecallerAndroidModule = NativeModules.TruecallerModule;
const TruecallerIOS = NativeModules.ReactNativeTruecaller;
export const useTruecaller = config => {
const [userProfile, setUserProfile] = useState(null);
const [error, setError] = useState(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.message);
setIsTruecallerInitialized(false);
}
}, [config]);
useEffect(() => {
let successListener;
let failureListener;
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 => {
// custom handler if provided, otherwise default handler
if (config.androidSuccessHandler) {
config.androidSuccessHandler(data);
} else {
handleAuthorizationSuccess(data);
}
});
failureListener = DeviceEventEmitter.addListener(TRUECALLER_ANDROID_EVENTS.FAILURE, err => {
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 => {
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 => {
try {
if (Platform.OS === 'android') {
const {
authorizationCode,
codeVerifier
} = data;
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));
}
setError(null);
} catch (err) {
setError(err.message);
setUserProfile(null);
}
};
const exchangeAuthorizationCodeForAccessToken = async (authorizationCode, codeVerifier) => {
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 => {
const response = await axios.get(TRUECALLER_API_URLS.USER_INFO_URL, {
headers: {
Authorization: `Bearer ${accessToken}`
}
});
return mapAndroidResponseToUserProfile(response.data);
};
const mapAndroidResponseToUserProfile = data => ({
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 => ({
firstName: data.firstName,
lastName: data.lastName,
email: data.email,
countryCode: data.countryCode,
gender: data.gender,
phoneNumber: data.phoneNumber
});
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.message);
}
}, [isTruecallerInitialized, config]);
return {
userProfile,
error,
isTruecallerInitialized,
initializeTruecallerSDK,
isSdkUsable,
openTruecallerForVerification
};
};
//# sourceMappingURL=useTruecaller.js.map