Files
address-verification-app/src/components/utlis/commonFunctions.ts
2023-10-10 18:25:14 +05:30

371 lines
11 KiB
TypeScript

import AsyncStorage from '@react-native-async-storage/async-storage';
import ReactNativeBlobUtil from 'react-native-blob-util';
import {
Address,
DOCUMENT_TYPE,
IDocument,
IPhoneSources,
PhoneNumber,
PhoneNumberSource,
TDocumentObj,
} from '../../screens/caseDetails/interface';
import { getPrefixBase64Image, LocalStorageKeys, MimeType } from '../../common/Constants';
import NetInfo from '@react-native-community/netinfo';
import Clipboard from '@react-native-clipboard/clipboard';
import { useWindowDimensions } from 'react-native';
import { GlobalDocumentMap } from '../../../App';
import { GenericType } from '../../common/GenericTypes';
import { CaseDetail } from '../../screens/caseDetails/interface';
import { logError } from './errorUtils';
import packageJson from '../../../package.json';
import { CaseAllocationType } from '../../screens/allCases/interface';
import { RouteProp } from '@react-navigation/native';
import crashlytics from '@react-native-firebase/crashlytics';
import { deflate } from 'react-native-gzip';
import { IGeolocationCoordinate } from '../../types/addressGeolocation.types';
const fs = ReactNativeBlobUtil.fs;
const RespHeaderContentTypeKey = 'Content-Type';
const DEFAULT_TEXT = '--';
const MAX_SHEET_HEIGHT_PERCENTAGE = 50;
export const RELATIVE_PATH_PREFIX = 'file://';
export const decideLoadingState = (textData: string): boolean => {
if (!textData) {
return true;
}
if (textData.includes('NaN') || textData.includes('undefined')) {
return true;
}
return false;
};
export const getCommunicationAddress = (address: Address) => {
if (!address) {
return '';
}
const { houseNumber, lineOne, lineTwo, locality, street, city, state, pinCode } = address;
return [houseNumber, lineOne, lineTwo, locality, street, city, state, pinCode]
.filter((element) => element)
.join(', ');
};
export const storeImageLocallyReturnRelativePath = async (imagePath: string) => {
if (!imagePath) return;
return ReactNativeBlobUtil.config({
fileCache: true,
})
.fetch('GET', imagePath)
.then((resp) => {
return RELATIVE_PATH_PREFIX + resp.path();
});
};
export const getBase64FromUrl = async (imagePath: string) => {
let contentType: MimeType;
return ReactNativeBlobUtil.config({
fileCache: true,
})
.fetch('GET', imagePath)
.then((resp) => {
if (resp) {
imagePath = resp.path();
contentType = resp.respInfo?.headers?.[RespHeaderContentTypeKey];
return resp.readFile('base64');
}
})
.then((base64) => {
fs.unlink(imagePath);
if (contentType) {
return `${getPrefixBase64Image(contentType)}${base64}`;
}
return;
});
};
export const getNetInfo = async () => {
const netInfo = await NetInfo.fetch();
return netInfo;
};
export const copyToClipboard = (text: string) => {
Clipboard.setString(text);
};
export const clearClipboard = () => {
Clipboard.setString('');
};
export const fetchCopiedText = async () => {
const text = await Clipboard.getString();
return text;
};
export const setAsyncStorageItem = async (key: string, value: any) => {
try {
const stringifiedValue = JSON.stringify(value);
await AsyncStorage.setItem(key, stringifiedValue);
} catch (err) {
console.error('JSON stringify errored', err);
}
return;
};
export const clearAllAsyncStorage = async () => {
try {
await AsyncStorage.clear();
} catch (err) {
// todo: add click-stream event
logError(err as Error, 'Error while cleaning AsyncStorage');
console.error('Error while cleaning AsyncStorage');
}
return;
};
export const sanitizeString = (str = '') => {
return str?.trim() || DEFAULT_TEXT;
};
export function toTileCase(text: string): string {
return text?.[0]?.toUpperCase() + text?.substring(1)?.toLowerCase() || text || '';
}
export const memoize = <T = any>(fn: Func<T>) => {
const cache = new Map();
const cached = function (this: any, val: T) {
return cache.has(val) ? cache.get(val) : cache.set(val, fn.call(this, val)) && cache.get(val);
};
cached.cache = cache;
return cached;
};
export function getAddressString(address?: Address): string {
if (!address) {
return 'Address not found';
}
const addressFirstLine = [address.pinCode, address.city].filter(Boolean).join(', ');
const presentationAddressList = [
addressFirstLine,
address.lineOne,
address.lineTwo,
toTileCase(address.source),
];
return presentationAddressList.filter(Boolean).join(' \n ');
}
export function getPhoneNumberString(phoneNumber?: PhoneNumber): string {
if (!phoneNumber) {
return 'PhoneNumber not found';
}
return `${phoneNumber?.number} ${getPhoneSourceString(phoneNumber?.sources)}`;
}
export const getPhoneSourceString = (sources: IPhoneSources[]) => {
if (sources?.length) {
return `(${sources.map((source) => source.text).join(', ')})`;
}
return '';
};
export const getPrimaryPhoneNumber = (phoneNumbers: PhoneNumber[] | null) => {
if (!phoneNumbers?.length) {
return '';
}
const index = phoneNumbers.findIndex((number) => {
const { sources } = number;
const isPrimaryNumber = sources.some((source) => source.type === PhoneNumberSource.PRIMARY);
return isPrimaryNumber;
});
if (index !== -1) {
return phoneNumbers[2]?.number;
}
return phoneNumbers[0]?.number;
};
export const getDynamicBottomSheetHeightPercentageFn = (headerOffset = 100, rowHeight = 50) => {
const SCREEN_HEIGHT = useWindowDimensions().height;
return (rowLength = 0) => {
const dynamicHeight = ((rowLength * rowHeight + headerOffset) / SCREEN_HEIGHT) * 100;
return Math.min(dynamicHeight, MAX_SHEET_HEIGHT_PERCENTAGE);
};
};
export const saveToGlobalDocumentMap = async (caseId: string, data: TDocumentObj) => {
if (!caseId) return;
GlobalDocumentMap[caseId] = data;
await setAsyncStorageItem(LocalStorageKeys.GLOBAL_DOCUMENT_MAP, GlobalDocumentMap);
};
export const allSettled = (promises: Promise<GenericType>[]) =>
Promise.all(
promises.map((p) =>
p
.then((value) => ({ status: 'fulfilled', value }))
.catch((value) => ({ status: 'rejected', value }))
)
);
export function isNullOrUndefined(val: any): boolean {
return val === undefined || val === null;
}
export const getLoanAccountNumber = (caseDetail: CaseDetail) => {
const { loanAccountNumber, loanDetails } = caseDetail ?? {};
return loanAccountNumber ?? loanDetails?.loanAccountNumber ?? '';
};
export function getAppVersion(): string {
return packageJson.version;
}
export const getDocumentList = (caseDetails: CaseDetail) => {
return caseDetails.caseType === CaseAllocationType.ADDRESS_VERIFICATION_CASE
? caseDetails.customerInfo?.documents
: caseDetails.documents;
};
export const findDocumentByDocumentType = (
documentList: IDocument[] = [],
documentType: DOCUMENT_TYPE
) => {
return documentList?.find((documentItem) => documentItem.type === documentType);
};
export const checkS3Url = async (url: string): Promise<boolean> => {
try {
const response = await fetch(url, { method: 'HEAD' });
return response.ok;
} catch (error) {
return false;
}
};
export function debounce(func: any, timeout = 1000) {
let timer: number;
return (...args: any) => {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
}
function memoizeValue<T extends (...args: any[]) => any>(func: T): T {
const cache: Record<string, any> = {};
return function (...args: Parameters<T>): ReturnType<T> {
const key = JSON.stringify(args);
if (cache[key]) {
return cache[key];
}
const result = func.apply(this, args);
cache[key] = result;
return result;
} as T;
}
export const getKeyByValue = memoizeValue(function (obj: Record<string, string>, value: string) {
for (let key in obj) {
const regex = /\{.*?\}/g;
const str = obj[key].replace(regex, '');
if (value.includes(str)) {
return key;
}
}
});
export const getEventNameFromAPIKey = (apiKey: string, isSuccess?: boolean) => {
return `FA_${apiKey}_${isSuccess ? 'SUCCESS' : 'FAILED'}`;
};
// takes params string like state=123&code=12456
export const getParamsObject = (paramsString: string) => {
const paramsArray = paramsString.split('&');
let pair = null,
data: Record<string, string> = {};
paramsArray.forEach((keyValueString) => {
pair = keyValueString.split('=');
if (pair?.length === 2) {
data[pair[0]] = pair[1];
}
});
return data;
};
export const isTimeDifferenceWithinRange = (time: string, rangeInMinutes: number): boolean => {
const providedTime = new Date(time).getTime();
const currentTime = new Date().getTime();
const timeDifferenceInMinutes = Math.abs(Math.round((currentTime - providedTime) / 1000 / 60));
return timeDifferenceInMinutes <= rangeInMinutes;
};
export const getScreenFocusListenerObj = ({ route }: { route: RouteProp<GenericType> }) => ({
focus: () => {
crashlytics().log(JSON.stringify(route));
},
});
export const convertTo24HourFormat = (time: string) => {
const [hourMinuteText, period] = time.split(' ');
let [hour, minutes] = hourMinuteText.split(':');
if (period === 'PM' && hour !== '12') {
hour = String(parseInt(hour, 10) + 12);
} else if (period === 'AM' && hour === '12') {
hour = '00';
}
return `${hour}:${minutes}`;
};
export const getGzipData = async (data: string) => {
try {
const compressed = await deflate(data);
return compressed;
} catch (_err) {
logError(_err as Error);
}
};
export const getMaxByPropFromList = (arr: GenericType, prop: string) => {
const mappedArray = arr.map((x: GenericType) => x[prop]);
const max = Math.max(...mappedArray);
return arr.find((x: GenericType) => x[prop] == max);
};
export const getGoogleMapUrl = (latitude: string | number, longitude: string | number) => {
if (!latitude || !longitude) return;
return `https://www.google.com/maps/search/${latitude},+${longitude}`;
};
export const isValidAmountEntered = (value: number) => {
return typeof value === 'number' && !isNaN(value);
};
function deg2rad(deg: number) {
return deg * (Math.PI / 180);
}
export function getDistanceFromLatLonInKm(
latLong1: IGeolocationCoordinate,
latLong2: IGeolocationCoordinate
) {
if (!latLong1.latitude || !latLong1.longitude || !latLong2.latitude || !latLong2.longitude)
return NaN;
const EARTH_RADIUS = 6371;
const deltaLat = deg2rad(latLong2.latitude - latLong1.latitude);
const deltaLon = deg2rad(latLong2.longitude - latLong1.longitude);
const intermediateResult =
Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
Math.cos(deg2rad(latLong1.latitude)) *
Math.cos(deg2rad(latLong2.latitude)) *
Math.sin(deltaLon / 2) *
Math.sin(deltaLon / 2);
const distance = 2 * Math.atan2(Math.sqrt(intermediateResult), Math.sqrt(1 - intermediateResult));
return EARTH_RADIUS * distance;
}