react-native-cashfree-pg-sdk
Version:
Cashfree PG Plugin for React Native
275 lines • 8.19 kB
JavaScript
import { TextInput } from 'react-native';
import React, { forwardRef } from 'react';
import { CFCardPayment, CFEnvironment } from 'cashfree-pg-api-contract';
import { CFPaymentGatewayService } from '../index';
function luhnCheck(cardNumber) {
if (cardNumber.length === 0) {
return false;
}
cardNumber = cardNumber.replace(/\s/g, ''); // Remove spaces
let sum = 0;
let isAlternate = false;
for (let i = cardNumber.length - 1; i >= 0; i--) {
let digit = parseInt(cardNumber[i], 10);
if (isAlternate) {
digit *= 2;
if (digit > 9) {
digit -= 9;
}
}
sum += digit;
isAlternate = !isAlternate;
}
return sum % 10 === 0;
}
function getInputValidationDetails(cardBinResponse) {
if (!cardBinResponse || !cardBinResponse.scheme) {
return null;
}
let schemeType = cardBinResponse.scheme.toLowerCase();
let inputValidationDetails;
switch (schemeType) {
case 'amex':
inputValidationDetails = {
max_input_length: 15,
cvv_length: 4
};
break;
case 'diners':
inputValidationDetails = {
max_input_length: 14,
cvv_length: 3
};
break;
default:
// Covers visa, mastercard, rupay, jcb, discover, and unknown schemes
inputValidationDetails = {
max_input_length: 16,
cvv_length: 3
};
}
return inputValidationDetails;
}
/**
* Fetching Tdr info with card bin data & cfSession object
* @param session : for payment sessionId & env
* @param bin : for card number
*/
async function getTDR(session, bin) {
const route = `/pg/sdk/js/${session.payment_session_id}/v2/tdr`;
const body = JSON.stringify({
code: bin,
code_type: 'bin'
});
return await getInfo(session.environment, route, body);
}
/**
* Fetching CardBin info with card bin data & cfSession object
* @param session : for payment sessionId & env
* @param bin : for card number
*/
async function getCardBin(session, bin) {
const route = `/pg/sdk/js/${session.payment_session_id}/cardBin`;
const body = JSON.stringify({
card_number: bin
});
return await getInfo(session.environment, route, body);
}
async function getInfo(env, route, bodyData) {
let baseUrl = 'https://api.cashfree.com';
if (env === CFEnvironment.SANDBOX) {
baseUrl = 'https://sandbox.cashfree.com';
}
const url = baseUrl + route;
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: bodyData
});
if (!response.ok) {
return null;
}
return await response.json();
} catch (error) {
return null;
}
}
const CardInput = /*#__PURE__*/forwardRef(({
cfSession,
cardListener,
style,
...props
}, ref) => {
const [inputNumber, setInputNumber] = React.useState('');
const inputNumberRef = React.useRef('');
const sessionRef = React.useRef(cfSession);
React.useImperativeHandle(ref, () => ({
doPayment,
doPaymentWithPaymentSessionId
}));
const tdrJsonRef = React.useRef(null);
const cardBinJsonRef = React.useRef(null);
const firstEightDigitsRef = React.useRef('');
const handleChange = React.useCallback(async cardNumber => {
let completeResponse = {};
const textWithoutSpaces = cardNumber.replaceAll(' ', '');
if (textWithoutSpaces.length === 0) setInputNumber('');
let formattedText = '';
/**
* Code to format card input number & set to input box
*/
for (let i = 0; i < textWithoutSpaces.length; i += 4) {
let end = i + 4;
if (end > textWithoutSpaces.length) {
end = textWithoutSpaces.length;
}
formattedText += textWithoutSpaces.substring(i, end);
if (end !== textWithoutSpaces.length) {
formattedText += ' ';
}
inputNumberRef.current = formattedText;
setInputNumber(prev => prev === formattedText ? prev : formattedText);
}
let tdrResponse = null;
let cardBinResponse = null;
/**
* Fetch Tdr & CardBin data & set to local variable
*/
async function fetchDataAndSet() {
await getTDR(cfSession, textWithoutSpaces).then(response => {
tdrResponse = response;
firstEightDigitsRef.current = textWithoutSpaces.substring(0, 8);
}).catch(() => {
tdrResponse = null;
});
await getCardBin(cfSession, textWithoutSpaces).then(response => {
cardBinResponse = response;
firstEightDigitsRef.current = textWithoutSpaces.substring(0, 8);
}).catch(() => {
cardBinResponse = null;
});
if (tdrResponse) {
tdrJsonRef.current = tdrResponse;
completeResponse.tdr_info = tdrJsonRef.current;
}
if (cardBinResponse) {
cardBinJsonRef.current = cardBinResponse;
completeResponse.card_bin_info = cardBinJsonRef.current;
completeResponse.input_validation = getInputValidationDetails(cardBinJsonRef.current);
}
}
if (textWithoutSpaces.length === 8) {
await fetchDataAndSet();
} else if (textWithoutSpaces.length > 8) {
if (firstEightDigitsRef.current === textWithoutSpaces.substring(0, 8)) {
completeResponse.tdr_info = tdrJsonRef.current;
completeResponse.card_bin_info = cardBinJsonRef.current;
completeResponse.input_validation = getInputValidationDetails(cardBinJsonRef.current);
} else {
tdrJsonRef.current = null;
cardBinJsonRef.current = null;
await fetchDataAndSet();
}
}
if (textWithoutSpaces.length < 8) {
tdrJsonRef.current = null;
cardBinJsonRef.current = null;
firstEightDigitsRef.current = '';
}
if (cardBinJsonRef.current !== null) {
completeResponse.card_network = cardBinJsonRef.current.scheme;
}
let luhnStatus = luhnCheck(textWithoutSpaces);
if (luhnStatus) {
completeResponse.luhn_check_info = 'SUCCESS';
if (textWithoutSpaces && textWithoutSpaces.length > 4) {
completeResponse.last_four_digit = textWithoutSpaces.substring(textWithoutSpaces.length - 4);
}
} else {
completeResponse.luhn_check_info = 'FAIL';
}
completeResponse.card_length = textWithoutSpaces.length;
return cardListener(JSON.stringify(completeResponse));
}, [cfSession, cardListener]);
const doPayment = cardInfo => {
try {
let cfCardNumber = inputNumberRef.current;
cardInfo.cardNumber = cfCardNumber.replaceAll(' ', '');
const cardPayment = new CFCardPayment(sessionRef.current, cardInfo);
CFPaymentGatewayService.makePayment(cardPayment);
} catch (e) {
console.log(e.message);
}
};
const doPaymentWithPaymentSessionId = (cardInfo, session) => {
try {
sessionRef.current = session;
doPayment(cardInfo);
} catch (e) {
console.log(e.message);
}
};
const handleSubmitEditingEvent = event => {
const newEvent = {
...event
};
delete newEvent.nativeEvent.text;
if (onSubmitEditing) {
onSubmitEditing(newEvent);
}
};
const handleEndEditingEvent = event => {
const newEvent = {
...event
};
delete newEvent.nativeEvent.text;
if (onEndEditing) {
onEndEditing(newEvent);
}
};
const handleFocusEvent = event => {
const newEvent = {
...event
};
delete newEvent.nativeEvent.text;
if (onFocus) {
onFocus(newEvent);
}
};
const handleBlurEvent = event => {
const newEvent = {
...event
};
delete newEvent.nativeEvent.text;
if (onBlur) {
onBlur(newEvent);
}
};
const InputComponent = TextInput;
const {
onChangeText,
onChange,
onSubmitEditing,
onEndEditing,
onFocus,
onBlur,
...otherProps
} = props;
return /*#__PURE__*/React.createElement(InputComponent, {
keyboardType: "numeric",
inputMode: 'numeric',
value: inputNumber,
onChangeText: handleChange,
onSubmitEditing: handleSubmitEditingEvent,
onEndEditing: handleEndEditingEvent,
onFocus: handleFocusEvent,
onBlur: handleBlurEvent,
style: style,
...otherProps
});
});
export default CardInput;
//# sourceMappingURL=CFCardComponent.js.map