@pngme/react-native-sms-pngme-android
Version:
Module for Pngme partners to build credit score from phone information
292 lines (253 loc) • 8.42 kB
text/typescript
import { NativeModules, Platform } from 'react-native';
const ANDROID_OS_NAME = 'android';
export type GoParams = {
clientKey: string;
firstName?: string;
lastName?: string;
email?: string;
phoneNumber?: string;
externalId: string;
companyName: string;
};
export type PngmeDialogStyle = {
primaryColor?: string;
backgroundColor?: string;
textColor?: string;
buttonBackgroundColor?: string;
buttonTextColor?: string;
titleTextSize?: number;
bodyTextSize?: number;
buttonTextSize?: number;
customTitle?: string;
customSmsDescription?: string;
customPrivacyDescription?: string;
customButtonText?: string;
buttonCornerRadius?: number;
buttonElevation?: number;
privacyPolicyUrl?: string;
eulaUrl?: string;
};
export type PngmeError = {
code: string;
message: string;
};
// Response constants
const SDK_FLOW_ERROR = 'E_ON_SDK';
const SDK_IOS_INCOMPATIBLE = 'E_IOS_IS_NOT_COMPATIBLE';
const SDK_SUCCESS = 'success';
const E_INVALID_PARAMS = 'E_INVALID_PARAMS';
const E_ACTIVITY_DOES_NOT_EXIST = 'E_ACTIVITY_DOES_NOT_EXIST';
/**
* Validate required parameters before calling SDK
*/
function validateParams(params: GoParams): PngmeError | null {
if (!params.clientKey || params.clientKey.trim() === '') {
return { code: E_INVALID_PARAMS, message: 'ClientKey is required' };
}
if (!params.externalId || params.externalId.trim() === '') {
return { code: E_INVALID_PARAMS, message: 'ExternalId is required' };
}
if (!params.companyName || params.companyName.trim() === '') {
return { code: E_INVALID_PARAMS, message: 'CompanyName is required' };
}
// Validate client key format (adjust as needed)
if (params.clientKey.length < 32) {
return { code: E_INVALID_PARAMS, message: 'ClientKey appears to be invalid (too short)' };
}
return null;
}
/**
* Simple status handling - the SDK only returns success or error codes
*/
function handleSDKResponse(status: string, errorMessage?: string): string {
if (status === SDK_SUCCESS) {
return status;
}
// For any non-success status, throw an error with descriptive message
const errorMsg = errorMessage || 'Unknown error occurred';
switch (status) {
case E_INVALID_PARAMS:
throw new Error(`Invalid Parameters: ${errorMsg}`);
case E_ACTIVITY_DOES_NOT_EXIST:
throw new Error('Activity Error: No valid Android activity found. Make sure you\'re calling this from a valid React Native screen.');
case SDK_IOS_INCOMPATIBLE:
throw new Error('Platform Error: This SDK is only compatible with Android devices.');
default:
throw new Error(`SDK Error: ${errorMsg}`);
}
}
/**
* Basic SDK integration - shows default Pngme dialog
*/
export async function go(params: GoParams): Promise<string> {
// Validate parameters first
const validationError = validateParams(params);
if (validationError) {
throw new Error(validationError.message);
}
if (Platform.OS !== ANDROID_OS_NAME) {
throw new Error('Platform Error: This SDK is only compatible with Android devices.');
}
return new Promise<string>((resolve, reject) => {
try {
const { SDKWrapper } = NativeModules;
if (!SDKWrapper) {
reject(new Error('SDK Error: SDKWrapper module not found. Make sure the native module is properly linked.'));
return;
}
console.log('Calling Pngme SDK with params:', JSON.stringify(params, null, 2));
SDKWrapper.go(params, (status: string, errorMessage?: string) => {
console.log('Pngme SDK Response:', { status, errorMessage });
try {
const result = handleSDKResponse(status, errorMessage);
resolve(result);
} catch (error) {
reject(error);
}
});
} catch (error) {
console.error('Error calling Pngme SDK:', error);
reject(new Error(`SDK Error: ${error instanceof Error ? error.message : 'Unknown error occurred'}`));
}
});
}
/**
* Backward compatibility - maps to standard go() method
* @deprecated Use go() or goWithStyle() instead
*/
export async function goWithCustomDialog(params: GoParams): Promise<string> {
console.warn('goWithCustomDialog is deprecated. Use go() or goWithStyle() instead.');
return go(params);
}
/**
* SDK integration with custom dialog styling
*/
export async function goWithStyle(params: GoParams, style: PngmeDialogStyle): Promise<string> {
// Validate parameters first
const validationError = validateParams(params);
if (validationError) {
throw new Error(validationError.message);
}
if (Platform.OS !== ANDROID_OS_NAME) {
throw new Error('Platform Error: This SDK is only compatible with Android devices.');
}
return new Promise<string>((resolve, reject) => {
try {
const { SDKWrapper } = NativeModules;
if (!SDKWrapper) {
reject(new Error('SDK Error: SDKWrapper module not found. Make sure the native module is properly linked.'));
return;
}
console.log('Calling Pngme SDK with style:', JSON.stringify({ params, style }, null, 2));
SDKWrapper.goWithStyle(params, style, (status: string, errorMessage?: string) => {
console.log('Pngme SDK with Style Response:', { status, errorMessage });
try {
const result = handleSDKResponse(status, errorMessage);
resolve(result);
} catch (error) {
reject(error);
}
});
} catch (error) {
console.error('Error calling Pngme SDK with style:', error);
reject(new Error(`SDK Error: ${error instanceof Error ? error.message : 'Unknown error occurred'}`));
}
});
}
/**
* Set a default style for all SDK dialogs
*/
export function setDefaultStyle(style: PngmeDialogStyle): void {
if (Platform.OS === ANDROID_OS_NAME) {
try {
const { SDKWrapper } = NativeModules;
if (SDKWrapper) {
SDKWrapper.setDefaultStyle(style);
console.log('Default style set successfully');
} else {
console.warn('SDKWrapper module not found');
}
} catch (error) {
console.warn('Error setting default style:', error);
}
}
}
/**
* Clear the default style and revert to original Pngme styling
*/
export function clearDefaultStyle(): void {
if (Platform.OS === ANDROID_OS_NAME) {
try {
const { SDKWrapper } = NativeModules;
if (SDKWrapper) {
SDKWrapper.clearDefaultStyle();
console.log('Default style cleared successfully');
} else {
console.warn('SDKWrapper module not found');
}
} catch (error) {
console.warn('Error clearing default style:', error);
}
}
}
/**
* Check if SMS permissions are granted
*/
export async function isPermissionGranted(): Promise<boolean> {
if (Platform.OS !== ANDROID_OS_NAME) {
return false;
}
try {
const { SDKWrapper } = NativeModules;
if (!SDKWrapper) {
console.warn('SDKWrapper module not found');
return false;
}
return await SDKWrapper.isPermissionGranted();
} catch (error) {
console.warn('Error on PngmeSDK - isPermissionGranted', error);
return false;
}
}
/**
* Get the current user's UUID
*/
export async function getUserUuid(): Promise<string | null> {
if (Platform.OS !== ANDROID_OS_NAME) {
return null;
}
try {
const { SDKWrapper } = NativeModules;
if (!SDKWrapper) {
console.warn('SDKWrapper module not found');
return null;
}
return await SDKWrapper.getUserUuid();
} catch (error) {
console.warn('Error on PngmeSDK - getUserUuid', error);
return null;
}
}
/**
* Enhanced SDK call with pre-flight checks
*/
export async function goWithPreflightChecks(params: GoParams, style?: PngmeDialogStyle): Promise<string> {
console.log('Starting Pngme SDK with preflight checks...');
// 2. Check permissions
const hasPermissions = await isPermissionGranted();
console.log(`SMS permissions granted: ${hasPermissions}`);
// 3. Call appropriate SDK method
if (style) {
return goWithStyle(params, style);
} else {
return go(params);
}
}
// Export response constants for client use
export const PNGME_RESPONSES = {
SUCCESS: SDK_SUCCESS,
ERROR: SDK_FLOW_ERROR,
IOS_INCOMPATIBLE: SDK_IOS_INCOMPATIBLE,
INVALID_PARAMS: E_INVALID_PARAMS,
ACTIVITY_DOES_NOT_EXIST: E_ACTIVITY_DOES_NOT_EXIST,
} as const;