From 01e66aa5be60e00b1b3776fa3a9e219a71242398 Mon Sep 17 00:00:00 2001 From: ChiragKV-Juspay Date: Tue, 17 Dec 2024 17:57:57 +0530 Subject: [PATCH 1/5] refactor: added submodule for hyperswitch-sdk-utils --- .gitmodules | 4 ++++ hyperswitch-sdk-utils | 1 + 2 files changed, 5 insertions(+) create mode 160000 hyperswitch-sdk-utils diff --git a/.gitmodules b/.gitmodules index e8625f07..abf2c816 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,7 @@ path = android url = git@github.com:juspay/hyperswitch-sdk-android.git branch = main +[submodule "hyperswitch-sdk-utils"] + path = hyperswitch-sdk-utils + url = git@github.com:juspay/hyperswitch-sdk-utils.git + branch = main diff --git a/hyperswitch-sdk-utils b/hyperswitch-sdk-utils new file mode 160000 index 00000000..13b4431e --- /dev/null +++ b/hyperswitch-sdk-utils @@ -0,0 +1 @@ +Subproject commit 13b4431e3b6bc245d6d220af9a65cfe132cf6108 From de63808ffc2b77688f3e78716051917759efe3a8 Mon Sep 17 00:00:00 2001 From: ChiragKV-Juspay Date: Wed, 18 Dec 2024 17:33:13 +0530 Subject: [PATCH 2/5] refactor: moved card cvc, card expiry validations and respective util functions to hyperswitch-sdk-utils --- rescript.json | 4 + src/components/elements/CardElement.res | 4 +- src/components/elements/CardFormUi.res | 3 + src/components/elements/PaymentSheetUi.res | 2 + src/hooks/AllPaymentHooks.res | 4 +- src/pages/payment/SaveCardsList.res | 7 +- src/pages/widgets/CardWidget.res | 4 +- src/utility/logics/PaymentUtils.res | 4 +- .../reusableCodeFromWeb/CardPattern.res | 103 ------------------ .../reusableCodeFromWeb/Validation.res | 81 +------------- 10 files changed, 25 insertions(+), 191 deletions(-) delete mode 100644 src/utility/reusableCodeFromWeb/CardPattern.res diff --git a/rescript.json b/rescript.json index 6d6a6477..c3677bc7 100644 --- a/rescript.json +++ b/rescript.json @@ -15,6 +15,10 @@ { "dir": "reactNativeWeb", "subdirs": true + }, + { + "dir": "hyperswitch-sdk-utils", + "subdirs": true } ], "bs-dependencies": [ diff --git a/src/components/elements/CardElement.res b/src/components/elements/CardElement.res index 9a17a7c1..e73a75cb 100644 --- a/src/components/elements/CardElement.res +++ b/src/components/elements/CardElement.res @@ -1,4 +1,6 @@ open Validation +open CardExpiryValidation + type cardFormType = {isZipAvailable: bool} type viewType = PaymentSheet | CardForm(cardFormType) @react.component @@ -83,7 +85,7 @@ let make = ( } let onChangeCvv = (text, cvvOrZipRef: React.ref>) => { let cvvData = formatCVCNumber(text, getCardBrand(cardData.cardNumber)) - let isthisValid = checkCardCVC(cvvData, getCardBrand(cardData.cardNumber)) + let isthisValid = CardCvcValidation.checkCardCVC(cvvData, getCardBrand(cardData.cardNumber)) if isthisValid { switch cvvOrZipRef.current->Nullable.toOption { | None => () diff --git a/src/components/elements/CardFormUi.res b/src/components/elements/CardFormUi.res index 0c06d7c3..8be3cc23 100644 --- a/src/components/elements/CardFormUi.res +++ b/src/components/elements/CardFormUi.res @@ -1,6 +1,9 @@ open ReactNative open Style open Validation +open CardCvcValidation +open ValidationUtils + @react.component let make = ( ~cardNumber, diff --git a/src/components/elements/PaymentSheetUi.res b/src/components/elements/PaymentSheetUi.res index 74319d74..f2ddd254 100644 --- a/src/components/elements/PaymentSheetUi.res +++ b/src/components/elements/PaymentSheetUi.res @@ -1,6 +1,8 @@ open ReactNative open Style open Validation +open CardCvcValidation +open ValidationUtils @react.component let make = ( diff --git a/src/hooks/AllPaymentHooks.res b/src/hooks/AllPaymentHooks.res index 3123b17d..5bb013e6 100644 --- a/src/hooks/AllPaymentHooks.res +++ b/src/hooks/AllPaymentHooks.res @@ -866,13 +866,13 @@ let useSavePaymentMethod = () => { let (nativeProp, _) = React.useContext(NativePropContext.nativePropContext) let (cardData, _) = React.useContext(CardDataContext.cardDataContext) - let (month, year) = Validation.getExpiryDates(cardData.expireDate) + let (month, year) = CardExpiryValidation.getExpiryDates(cardData.expireDate) let payment_method_data = [ ( "card", [ - ("card_number", cardData.cardNumber->Validation.clearSpaces->JSON.Encode.string), + ("card_number", cardData.cardNumber->ValidationUtils.clearSpaces->JSON.Encode.string), ("card_exp_month", month->JSON.Encode.string), ("card_exp_year", year->JSON.Encode.string), ] diff --git a/src/pages/payment/SaveCardsList.res b/src/pages/payment/SaveCardsList.res index 5a2d3bf0..96ce2032 100644 --- a/src/pages/payment/SaveCardsList.res +++ b/src/pages/payment/SaveCardsList.res @@ -1,5 +1,6 @@ open ReactNative open Style +open CardCvcValidation module CVVComponent = { @react.component @@ -17,7 +18,7 @@ module CVVComponent = { isCvcFocus || savedCardCvv->Option.isNone ? true : savedCardCvv->Option.getOr("")->String.length > 0 && - Validation.cvcNumberInRange(savedCardCvv->Option.getOr(""), cardScheme) + cvcNumberInRange(savedCardCvv->Option.getOr(""), cardScheme) let localeObject = GetLocale.useGetLocalObj() @@ -59,7 +60,7 @@ module CVVComponent = { secureTextEntry=true textColor={isCvcValid ? component.color : dangerColor} iconRight=CustomIcon({ - Validation.checkCardCVC(savedCardCvv->Option.getOr(""), cardScheme) + checkCardCVC(savedCardCvv->Option.getOr(""), cardScheme) ? : }) @@ -230,7 +231,7 @@ module PaymentMethodListView = { | "NotCard" => true | _ => switch savedCardCvv { - | Some(cvv) => cvv->String.length > 0 && Validation.cvcNumberInRange(cvv, cardScheme) + | Some(cvv) => cvv->String.length > 0 && cvcNumberInRange(cvv, cardScheme) | None => !(pmObject->PaymentUtils.checkIsCVCRequired) } } diff --git a/src/pages/widgets/CardWidget.res b/src/pages/widgets/CardWidget.res index 36f647a4..53e51b49 100644 --- a/src/pages/widgets/CardWidget.res +++ b/src/pages/widgets/CardWidget.res @@ -41,13 +41,13 @@ let make = () => { | _ => handleSuccessFailure(~apiResStatus=status, ()) } } - let (month, year) = Validation.getExpiryDates(expireDate) + let (month, year) = CardExpiryValidation.getExpiryDates(expireDate) let payment_method_data = [ ( prop.payment_method, [ - ("card_number", cardNumber->Validation.clearSpaces->JSON.Encode.string), + ("card_number", cardNumber->ValidationUtils.clearSpaces->JSON.Encode.string), ("card_exp_month", month->JSON.Encode.string), ("card_exp_year", year->JSON.Encode.string), ("card_holder_name", ""->JSON.Encode.string), diff --git a/src/utility/logics/PaymentUtils.res b/src/utility/logics/PaymentUtils.res index 95b9f28c..ac1f92b4 100644 --- a/src/utility/logics/PaymentUtils.res +++ b/src/utility/logics/PaymentUtils.res @@ -20,13 +20,13 @@ let generatePaymentMethodData = ( ~cardHolderName: option<'a>, ~nickname: option<'a>, ) => { - let (month, year) = Validation.getExpiryDates(cardData.expireDate) + let (month, year) = CardExpiryValidation.getExpiryDates(cardData.expireDate) [ ( prop.payment_method, [ - ("card_number", cardData.cardNumber->Validation.clearSpaces->JSON.Encode.string), + ("card_number", cardData.cardNumber->ValidationUtils.clearSpaces->JSON.Encode.string), ("card_exp_month", month->JSON.Encode.string), ("card_exp_year", year->JSON.Encode.string), ( diff --git a/src/utility/reusableCodeFromWeb/CardPattern.res b/src/utility/reusableCodeFromWeb/CardPattern.res deleted file mode 100644 index cecf56f7..00000000 --- a/src/utility/reusableCodeFromWeb/CardPattern.res +++ /dev/null @@ -1,103 +0,0 @@ -type patterns = { - issuer: string, - pattern: Js.Re.t, - cvcLength: array, - length: array, - maxCVCLenth: int, - pincodeRequired: bool, -} -type card = {details: array} -let defaultCardPattern = { - issuer: "", - pattern: %re("/^[0-9]/"), - cvcLength: [3], - maxCVCLenth: 3, - length: [16], - pincodeRequired: false, -} -let cardPatterns = [ - { - issuer: "Maestro", - pattern: %re( - "/^(5018|5081|5044|504681|504993|5020|502260|5038|603845|603123|6304|6759|676[1-3]|6220|504834|504817|504645|504775|600206|627741)/" - ), - cvcLength: [3, 4], - length: [12, 13, 14, 15, 16, 17, 18, 19], - maxCVCLenth: 4, - pincodeRequired: true, - }, - { - issuer: "RuPay", - pattern: %re( - "/^(508227|508[5-9]|603741|60698[5-9]|60699|607[0-8]|6079[0-7]|60798[0-4]|60800[1-9]|6080[1-9]|608[1-4]|608500|6521[5-9]|652[2-9]|6530|6531[0-4]|817290|817368|817378|353800)/" - ), - cvcLength: [3], - length: [16], - maxCVCLenth: 3, - pincodeRequired: false, - }, - { - issuer: "DinersClub", - pattern: %re("/^(36|38|30[0-5])/"), - cvcLength: [3], - maxCVCLenth: 3, - length: [14, 15, 16, 17, 18, 19], - pincodeRequired: false, - }, - { - issuer: "Discover", - pattern: %re("/^(6011|65|64[4-9]|622)/"), - cvcLength: [3], - length: [16], - maxCVCLenth: 3, - pincodeRequired: true, - }, - { - issuer: "Mastercard", - pattern: %re("/^5[1-5]/"), - cvcLength: [3], - maxCVCLenth: 3, - length: [16], - pincodeRequired: true, - }, - { - issuer: "AmericanExpress", - pattern: %re("/^3[47]/"), - cvcLength: [3, 4], - length: [14, 15], - maxCVCLenth: 4, - pincodeRequired: true, - }, - { - issuer: "Visa", - pattern: %re("/^4/"), - cvcLength: [3], - length: [13, 14, 15, 16, 19], - maxCVCLenth: 3, - pincodeRequired: true, - }, - { - issuer: "SODEXO", - pattern: %re("/^(637513)/"), - cvcLength: [3], - length: [16], - maxCVCLenth: 3, - pincodeRequired: false, - }, - { - issuer: "BAJAJ", - pattern: %re("/^(203040)/"), - cvcLength: [3], - maxCVCLenth: 3, - length: [16], - pincodeRequired: true, - }, - { - issuer: "JCB", - pattern: %re("/^35/"), - cvcLength: [3], - maxCVCLenth: 3, - length: [16], - pincodeRequired: false, - }, -] diff --git a/src/utility/reusableCodeFromWeb/Validation.res b/src/utility/reusableCodeFromWeb/Validation.res index f17ac1cd..778c7cf1 100644 --- a/src/utility/reusableCodeFromWeb/Validation.res +++ b/src/utility/reusableCodeFromWeb/Validation.res @@ -1,3 +1,5 @@ +open ValidationUtils + type cardIssuer = | VISA | MASTERCARD @@ -11,8 +13,6 @@ type cardIssuer = | JCB | NOTFOUND -let toInt = val => val->Int.fromString->Option.getOr(0) - let cardType = val => { switch val->String.toUpperCase { | "VISA" => VISA @@ -29,20 +29,6 @@ let cardType = val => { } } -let getobjFromCardPattern = cardBrand => { - let patternsDict = CardPattern.cardPatterns - patternsDict - ->Array.filter(item => { - cardBrand === item.issuer - }) - ->Array.get(0) - ->Option.getOr(CardPattern.defaultCardPattern) -} - -let clearSpaces = value => { - value->String.replaceRegExp(%re("/\D+/g"), "") -} - let slice = (val, start: int, end: int) => { val->String.slice(~start, ~end) } @@ -54,20 +40,7 @@ let getStrFromIndex = (arr: array, index) => { let formatCVCNumber = (val, cardType) => { let clearValue = val->clearSpaces let obj = getobjFromCardPattern(cardType) - clearValue->slice(0, obj.maxCVCLenth) -} - -let getCurrentMonthAndYear = (dateTimeIsoString: string) => { - let tempTimeDateString = dateTimeIsoString->String.replace("Z", "") - let tempTimeDate = tempTimeDateString->String.split("T") - - let date = tempTimeDate->Array.get(0)->Option.getOr("") - let dateComponents = date->String.split("-") - - let currentMonth = dateComponents->Array.get(1)->Option.getOr("") - let currentYear = dateComponents->Array.get(0)->Option.getOr("") - - (currentMonth->toInt, currentYear->toInt) + clearValue->slice(0, obj.maxCVCLength) } let formatCardNumber = (val, cardType) => { @@ -95,20 +68,6 @@ let formatCardNumber = (val, cardType) => { formatedCard->String.trim } -let splitExpiryDates = val => { - let split = val->String.split("/") - let value = split->Array.map(item => item->String.trim) - let month = value->Array.get(0)->Option.getOr("") - let year = value->Array.get(1)->Option.getOr("") - (month, year) -} -let getExpiryDates = val => { - let date = Date.make()->Date.toISOString - let (month, year) = splitExpiryDates(val) - let (_, currentYear) = getCurrentMonthAndYear(date) - let prefix = currentYear->Int.toString->String.slice(~start=0, ~end=2) - (month, `${prefix}${year}`) -} let formatCardExpiryNumber = val => { let clearValue = val->clearSpaces @@ -250,22 +209,6 @@ let calculateLuhn = value => { // } // } -let getExpiryValidity = cardExpiry => { - let date = Date.make()->Date.toISOString - let (month, year) = getExpiryDates(cardExpiry) - let (currentMonth, currentYear) = getCurrentMonthAndYear(date) - let valid = if currentYear == year->toInt && month->toInt >= currentMonth && month->toInt <= 12 { - true - } else if ( - year->toInt > currentYear && year->toInt < 2075 && month->toInt >= 1 && month->toInt <= 12 - ) { - true - } else { - false - } - valid -} - // let max = (a, b) => { // a > b ? a : b // } @@ -284,17 +227,6 @@ let getExpiryValidity = cardExpiry => { // } // } -let cvcNumberInRange = (val, cardBrand) => { - let clearValue = val->clearSpaces - let obj = getobjFromCardPattern(cardBrand) - let cvcLengthInRange = - obj.cvcLength - ->Array.find(item => { - clearValue->String.length == item - }) - ->Option.isSome - cvcLengthInRange -} // let genreateFontsLink = (fonts: array) => { // if fonts->Array.length > 0 { // fonts @@ -391,13 +323,6 @@ let cardValid = (cardNumber, cardBrand) => { // thirdIframeVal === "" ? secondIframeVal === "" ? firstIframeVal : secondIframeVal : thirdIframeVal // } -let checkCardCVC = (cvcNumber, cardBrand) => { - cvcNumber->String.length > 0 && cvcNumberInRange(cvcNumber, cardBrand) -} -let checkCardExpiry = expiry => { - expiry->String.length > 0 && getExpiryValidity(expiry) -} - // let commonKeyDownEvent = (ev, srcRef, destRef, srcEle, destEle, setEle) => { // let key = ReactEvent.Keyboard.keyCode(ev) // if key == 8 && srcEle == "" { From a28ff5ad2b682059fe65df992fe864ded3db4257 Mon Sep 17 00:00:00 2001 From: ChiragKV-Juspay Date: Thu, 19 Dec 2024 17:24:54 +0530 Subject: [PATCH 3/5] refactor: moved card number and email validations to hyperswitch-sdk-utils --- src/components/common/ValidationFunctions.res | 16 -------- src/components/elements/CardElement.res | 2 +- src/components/elements/CardFormUi.res | 1 + src/components/elements/PaymentSheetUi.res | 1 + src/pages/payment/Redirect.res | 2 +- src/types/RequiredFieldsTypes.res | 2 +- .../reusableCodeFromWeb/Validation.res | 40 ------------------- 7 files changed, 5 insertions(+), 59 deletions(-) diff --git a/src/components/common/ValidationFunctions.res b/src/components/common/ValidationFunctions.res index 920e6ab3..07fbb019 100644 --- a/src/components/common/ValidationFunctions.res +++ b/src/components/common/ValidationFunctions.res @@ -1,19 +1,3 @@ -let isValidEmail = text => { - switch text->String.match( - %re( - "/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/" - ), - ) { - | Some(_match) => Some(true) - | None => - if text->String.length == 0 { - None - } else { - Some(false) - } - } -} - let isValidZip = (~zipCode, ~country) => { let countryObj = Country.country diff --git a/src/components/elements/CardElement.res b/src/components/elements/CardElement.res index e73a75cb..cee17a5c 100644 --- a/src/components/elements/CardElement.res +++ b/src/components/elements/CardElement.res @@ -1,6 +1,6 @@ open Validation open CardExpiryValidation - +open CardNumberValidation type cardFormType = {isZipAvailable: bool} type viewType = PaymentSheet | CardForm(cardFormType) @react.component diff --git a/src/components/elements/CardFormUi.res b/src/components/elements/CardFormUi.res index 8be3cc23..78026d57 100644 --- a/src/components/elements/CardFormUi.res +++ b/src/components/elements/CardFormUi.res @@ -3,6 +3,7 @@ open Style open Validation open CardCvcValidation open ValidationUtils +open CardNumberValidation @react.component let make = ( diff --git a/src/components/elements/PaymentSheetUi.res b/src/components/elements/PaymentSheetUi.res index f2ddd254..8cfacbb9 100644 --- a/src/components/elements/PaymentSheetUi.res +++ b/src/components/elements/PaymentSheetUi.res @@ -3,6 +3,7 @@ open Style open Validation open CardCvcValidation open ValidationUtils +open CardNumberValidation @react.component let make = ( diff --git a/src/pages/payment/Redirect.res b/src/pages/payment/Redirect.res index 70e9dc79..8cc378d3 100644 --- a/src/pages/payment/Redirect.res +++ b/src/pages/payment/Redirect.res @@ -802,7 +802,7 @@ let make = ( } let handlePressEmail = text => { - setIsEmailValid(_ => text->ValidationFunctions.isValidEmail) + setIsEmailValid(_ => text->EmailValidation.isEmailValid) setEmail(_ => Some(text)) } let handlePressName = text => { diff --git a/src/types/RequiredFieldsTypes.res b/src/types/RequiredFieldsTypes.res index bad9aaa0..ff218f58 100644 --- a/src/types/RequiredFieldsTypes.res +++ b/src/types/RequiredFieldsTypes.res @@ -218,7 +218,7 @@ let checkIsValid = ( } else { switch field_type { | Email => - switch text->ValidationFunctions.isValidEmail { + switch text->EmailValidation.isEmailValid { | Some(false) => Some(localeObject.emailInvalidText) | Some(true) => None | None => Some(localeObject.emailEmptyText) diff --git a/src/utility/reusableCodeFromWeb/Validation.res b/src/utility/reusableCodeFromWeb/Validation.res index 778c7cf1..572c9ed0 100644 --- a/src/utility/reusableCodeFromWeb/Validation.res +++ b/src/utility/reusableCodeFromWeb/Validation.res @@ -152,37 +152,6 @@ let getCardBrand = cardNumber => { } } -let calculateLuhn = value => { - let card = value->clearSpaces - - let splitArr = card->String.split("") - splitArr->Array.reverse - let unCheckArr = splitArr->Array.filterWithIndex((_, i) => { - mod(i, 2) == 0 - }) - let checkArr = - splitArr - ->Array.filterWithIndex((_, i) => { - mod(i + 1, 2) == 0 - }) - ->Array.map(item => { - let val = item->toInt - let double = val * 2 - if double > 9 { - let str = double->Int.toString - let arr = str->String.split("") - (arr->Array.get(0)->Option.getOr("")->toInt + arr[1]->Option.getOr("")->toInt)->Int.toString - } else { - double->Int.toString - } - }) - - let sumofCheckArr = Array.reduce(checkArr, 0, (acc, val) => acc + val->toInt) - let sumofUnCheckedArr = Array.reduce(unCheckArr, 0, (acc, val) => acc + val->toInt) - let totalSum = sumofCheckArr + sumofUnCheckedArr - mod(totalSum, 10) == 0 -} - // let getCardBrandIcon = (cardType, paymentType) => { // open CardThemeType // switch cardType { @@ -255,21 +224,12 @@ let calculateLuhn = value => { // ->ignore // } // } -let maxCardLength = cardBrand => { - let obj = getobjFromCardPattern(cardBrand) - Array.reduce(obj.length, 0, (acc, val) => acc > val ? acc : val) -} // let cardValid = (cardNumber, cardBrand) => { // let clearValue = cardNumber->clearSpaces // Array.includes(getobjFromCardPattern(cardBrand).length, clearValue->String.length) && // calculateLuhn(cardNumber) // } -let cardValid = (cardNumber, cardBrand) => { - let clearValueLength = cardNumber->clearSpaces->String.length - (clearValueLength == maxCardLength(cardBrand) || - (cardBrand === "Visa" && clearValueLength == 16)) && calculateLuhn(cardNumber) -} // let blurRef = (ref: React.ref>) => { // ref.current->Nullable.toOption->Option.forEach(input => input->blur)->ignore From 18b8b5a0b0d2d54654125fd8eb1cb124642a8773 Mon Sep 17 00:00:00 2001 From: ChiragKV-Juspay Date: Fri, 20 Dec 2024 12:48:16 +0530 Subject: [PATCH 4/5] refactor: moved all Validation util functions to hyperswitch-sdk-utils --- src/components/elements/CardElement.res | 2 +- src/components/elements/CardFormUi.res | 1 - src/components/elements/PaymentSheetUi.res | 1 - src/pages/payment/SaveCardsList.res | 3 +- .../reusableCodeFromWeb/Validation.res | 374 ------------------ 5 files changed, 3 insertions(+), 378 deletions(-) delete mode 100644 src/utility/reusableCodeFromWeb/Validation.res diff --git a/src/components/elements/CardElement.res b/src/components/elements/CardElement.res index cee17a5c..4a723b0e 100644 --- a/src/components/elements/CardElement.res +++ b/src/components/elements/CardElement.res @@ -1,4 +1,4 @@ -open Validation +open ValidationUtils open CardExpiryValidation open CardNumberValidation type cardFormType = {isZipAvailable: bool} diff --git a/src/components/elements/CardFormUi.res b/src/components/elements/CardFormUi.res index 78026d57..de11401c 100644 --- a/src/components/elements/CardFormUi.res +++ b/src/components/elements/CardFormUi.res @@ -1,6 +1,5 @@ open ReactNative open Style -open Validation open CardCvcValidation open ValidationUtils open CardNumberValidation diff --git a/src/components/elements/PaymentSheetUi.res b/src/components/elements/PaymentSheetUi.res index 8cfacbb9..84cc33b2 100644 --- a/src/components/elements/PaymentSheetUi.res +++ b/src/components/elements/PaymentSheetUi.res @@ -1,6 +1,5 @@ open ReactNative open Style -open Validation open CardCvcValidation open ValidationUtils open CardNumberValidation diff --git a/src/pages/payment/SaveCardsList.res b/src/pages/payment/SaveCardsList.res index 96ce2032..6e994d35 100644 --- a/src/pages/payment/SaveCardsList.res +++ b/src/pages/payment/SaveCardsList.res @@ -24,7 +24,8 @@ module CVVComponent = { let errorMsgText = !isCvcValid ? Some(localeObject.inCompleteCVCErrorText) : None - let onCvvChange = cvv => setSavedCardCvv(_ => Some(Validation.formatCVCNumber(cvv, cardScheme))) + let onCvvChange = cvv => + setSavedCardCvv(_ => Some(ValidationUtils.formatCVCNumber(cvv, cardScheme))) { isPaymentMethodSelected diff --git a/src/utility/reusableCodeFromWeb/Validation.res b/src/utility/reusableCodeFromWeb/Validation.res deleted file mode 100644 index 572c9ed0..00000000 --- a/src/utility/reusableCodeFromWeb/Validation.res +++ /dev/null @@ -1,374 +0,0 @@ -open ValidationUtils - -type cardIssuer = - | VISA - | MASTERCARD - | AMEX - | MAESTRO - | DINERSCLUB - | DISCOVER - | BAJAJ - | SODEXO - | RUPAY - | JCB - | NOTFOUND - -let cardType = val => { - switch val->String.toUpperCase { - | "VISA" => VISA - | "MASTERCARD" => MASTERCARD - | "AMEX" => AMEX - | "MAESTRO" => MAESTRO - | "DINERSCLUB" => DINERSCLUB - | "DISCOVER" => DISCOVER - | "BAJAJ" => BAJAJ - | "SODEXO" => SODEXO - | "RUPAY" => RUPAY - | "JCB" => JCB - | _ => NOTFOUND - } -} - -let slice = (val, start: int, end: int) => { - val->String.slice(~start, ~end) -} - -let getStrFromIndex = (arr: array, index) => { - arr->Array.get(index)->Option.getOr("") -} - -let formatCVCNumber = (val, cardType) => { - let clearValue = val->clearSpaces - let obj = getobjFromCardPattern(cardType) - clearValue->slice(0, obj.maxCVCLength) -} - -let formatCardNumber = (val, cardType) => { - let clearValue = val->clearSpaces - let formatedCard = switch cardType { - | AMEX => `${clearValue->slice(0, 4)} ${clearValue->slice(4, 10)} ${clearValue->slice(10, 15)}` - | DINERSCLUB => - `${clearValue->slice(0, 4)} ${clearValue->slice(4, 10)} ${clearValue->slice(10, 14)}` - | MASTERCARD - | DISCOVER - | SODEXO - | RUPAY - | VISA => - `${clearValue->slice(0, 4)} ${clearValue->slice(4, 8)} ${clearValue->slice( - 8, - 12, - )} ${clearValue->slice(12, 16)} ${clearValue->slice(16, 19)}` - - | _ => - `${clearValue->slice(0, 4)} ${clearValue->slice(4, 8)} ${clearValue->slice( - 8, - 12, - )} ${clearValue->slice(12, 19)}` - } - - formatedCard->String.trim -} - -let formatCardExpiryNumber = val => { - let clearValue = val->clearSpaces - let expiryVal = clearValue->toInt - let formatted = if expiryVal >= 2 && expiryVal <= 9 && clearValue->String.length == 1 { - `0${clearValue} / ` - } else if clearValue->String.length == 2 && expiryVal > 12 { - let val = clearValue->String.split("") - `0${val->getStrFromIndex(0)} / ${val->getStrFromIndex(1)}` - } else { - clearValue - } - - if clearValue->String.length >= 3 { - `${formatted->slice(0, 2)} / ${formatted->slice(2, 4)}` - } else { - formatted - } -} - -let getCardBrand = cardNumber => { - try { - let card = cardNumber->String.replaceRegExp(%re("/[^\d]/g"), "") - let rupayRanges = [ - (508227, 508227), - (508500, 508999), - (603741, 603741), - (606985, 607384), - (607385, 607484), - (607485, 607984), - (608001, 608100), - (608101, 608200), - (608201, 608300), - (608301, 608350), - (608351, 608500), - (652150, 652849), - (652850, 653049), - (653050, 653149), - (817290, 817290), - (817368, 817368), - (817378, 817378), - (353800, 353800), - ] - - let masterCardRanges = [(222100, 272099)] - - let doesFallInRange = (cardRanges, isin) => { - let intIsin = - isin - ->String.replaceRegExp(%re("/[^\d]/g"), "") - ->String.substring(~start=0, ~end=6) - ->Int.fromString - ->Option.getOr(0) - - let range = cardRanges->Array.map(currCardRange => { - let (min, max) = currCardRange - - intIsin >= min && intIsin <= max - }) - range->Array.includes(true) - } - let patternsDict = CardPattern.cardPatterns - if doesFallInRange(rupayRanges, card) { - "RUPAY" - } else if doesFallInRange(masterCardRanges, card) { - "MASTERCARD" - } else { - patternsDict - ->Array.map(item => { - if String.match(card, item.pattern)->Option.isSome { - item.issuer - } else { - "" - } - }) - ->Array.filter(item => item !== "") - ->Array.get(0) - ->Option.getOr("") - } - } catch { - | _error => "" - } -} - -// let getCardBrandIcon = (cardType, paymentType) => { -// open CardThemeType -// switch cardType { -// | VISA => -// | MASTERCARD => -// | AMEX => -// | MAESTRO => -// | DINERSCLUB => -// | DISCOVER => -// | BAJAJ => -// | SODEXO => -// | RUPAY => -// | JCB => -// | NOTFOUND => -// switch paymentType { -// | Payment => -// | Card -// | CardNumberElement -// | CardExpiryElement -// | CardCVCElement -// | NONE => -// -// } -// } -// } - -// let max = (a, b) => { -// a > b ? a : b -// } - -// let getMaxLength = val => { -// let obj = getobjFromCardPattern(val->getCardBrand) -// let maxValue = obj.length->Array.reduce(0, max) -// if maxValue <= 12 { -// maxValue + 2 -// } else if maxValue <= 16 { -// maxValue + 3 -// } else if maxValue <= 19 { -// maxValue + 4 -// } else { -// maxValue + 2 -// } -// } - -// let genreateFontsLink = (fonts: array) => { -// if fonts->Array.length > 0 { -// fonts -// ->Array.map(item => -// if item.cssSrc != "" { -// let link = document["createElement"](. "link") -// link["href"] = item.cssSrc -// link["rel"] = "stylesheet" -// document["body"]["appendChild"](. link) -// } else if item.family != "" && item.src != "" { -// let newStyle = document["createElement"](. "style") -// newStyle["appendChild"](. -// document["createTextNode"](. -// `\ -// @font-face {\ -// font-family: "${item.family}";\ -// src: url(${item.src});\ -// font-weight: "${item.weight}";\ -// }\ -// `, -// ), -// )->ignore -// document["body"]["appendChild"](. newStyle) -// } -// ) -// ->ignore -// } -// } - -// let cardValid = (cardNumber, cardBrand) => { -// let clearValue = cardNumber->clearSpaces -// Array.includes(getobjFromCardPattern(cardBrand).length, clearValue->String.length) && -// calculateLuhn(cardNumber) -// } - -// let blurRef = (ref: React.ref>) => { -// ref.current->Nullable.toOption->Option.forEach(input => input->blur)->ignore -// } -// let handleInputFocus = ( -// ~currentRef: React.ref>, -// ~destinationRef: React.ref>, -// ) => { -// let optionalRef = destinationRef.current->Nullable.toOption -// switch optionalRef { -// | Some(_) => optionalRef->Option.forEach(input => input->focus)->ignore -// | None => blurRef(currentRef) -// } -// } - -// let getCardElementValue = (iframeId, key) => { -// let firstIframeVal = if (Window.parent->Window.frames)["0"]->Window.name !== iframeId { -// switch (Window.parent->Window.frames)["0"] -// ->Window.document -// ->Window.getElementById(key) -// ->Nullable.toOption { -// | Some(dom) => dom->Window.value -// | None => "" -// } -// } else { -// "" -// } -// let secondIframeVal = if (Window.parent->Window.frames)["1"]->Window.name !== iframeId { -// switch (Window.parent->Window.frames)["1"] -// ->Window.document -// ->Window.getElementById(key) -// ->Nullable.toOption { -// | Some(dom) => dom->Window.value -// | None => "" -// } -// } else { -// "" -// } - -// let thirdIframeVal = if (Window.parent->Window.frames)["2"]->Window.name !== iframeId { -// switch (Window.parent->Window.frames)["2"] -// ->Window.document -// ->Window.getElementById(key) -// ->Nullable.toOption { -// | Some(dom) => dom->Window.value -// | None => "" -// } -// } else { -// "" -// } -// thirdIframeVal === "" ? secondIframeVal === "" ? firstIframeVal : secondIframeVal : thirdIframeVal -// } - -// let commonKeyDownEvent = (ev, srcRef, destRef, srcEle, destEle, setEle) => { -// let key = ReactEvent.Keyboard.keyCode(ev) -// if key == 8 && srcEle == "" { -// handleInputFocus(~currentRef=srcRef, ~destinationRef=destRef) -// setEle(_ => slice(destEle, 0, -1)) -// ev->ReactEvent.Keyboard.preventDefault -// } -// } - -// let pincodeVisibility = cardNumber => { -// let brand = getCardBrand(cardNumber) -// let brandPattern = -// CardPattern.cardPatterns -// ->Array.filter(obj => obj.issuer == brand) -// ->Array.get(0) -// ->Option.getOr(CardPattern.defaultCardPattern) -// brandPattern.pincodeRequired -// } - -// let swapCardOption = (cardOpts: array, dropOpts: array, selectedOption: string) => { -// let popEle = Array.pop(cardOpts) -// dropOpts->Array.push(popEle->Option.getOr("")) -// cardOpts->Array.push(selectedOption) -// let temp: array = dropOpts->Array.filter(item => item != selectedOption) -// (cardOpts, temp) -// } - -// let setCardValid = (cardnumber, setIsCardValid) => { -// let cardBrand = getCardBrand(cardnumber) -// if cardValid(cardnumber, cardBrand) { -// setIsCardValid(_ => Some(true)) -// } else if ( -// !cardValid(cardnumber, cardBrand) && cardnumber->String.length == maxCardLength(cardBrand) -// ) { -// setIsCardValid(_ => Some(false)) -// } else if !(cardnumber->String.length == maxCardLength(cardBrand)) { -// setIsCardValid(_ => None) -// } -// } - -// let setExpiryValid = (expiry, setIsExpiryValid) => { -// if isExipryValid(expiry) { -// setIsExpiryValid(_ => Some(true)) -// } else if !getExpiryValidity(expiry) && isExipryComplete(expiry) { -// setIsExpiryValid(_ => Some(false)) -// } else if !isExipryComplete(expiry) { -// setIsExpiryValid(_ => None) -// } -// } -// let getLayoutClass = layout => { -// open PaymentType -// switch layout { -// | ObjectLayout(obj) => obj -// | StringLayout(str) => { -// ...defaultLayout, -// type_: str, -// } -// } -// } - -// let getAllBanknames = obj => { -// obj->Array.reduce([], (acc, item: PaymentMethodListType.bankNames) => { -// item.bank_name->Array.map(val => acc->Array.push(val))->ignore -// acc -// }) -// } - -// let getConnector = (bankList, selectedBank, banks, default) => { -// bankList -// ->Array.filter((item: PaymentMethodListType.bankNames) => { -// item.bank_name->Array.includes(selectedBank->Utils.getBankKeys(banks, default)) -// }) -// ->Array.get(0) -// ->Option.getOr(PaymentMethodListType.deafultBankNames) -// } -// let getAllConnectors = obj => { -// obj->Array.reduce([], (acc, item: PaymentMethodListType.bankNames) => { -// item.eligible_connectors->Array.map(val => acc->Array.push(val))->ignore -// acc -// }) -// } - -// let clientTimeZone = dateTimeFormat(.).resolvedOptions(.).timeZone -// let clientCountry = Utils.getClientCountry(clientTimeZone) - -// let postalRegex = (postalCodes: array) => { -// let countryPostal = Utils.getCountryPostal(clientCountry.isoAlpha2, postalCodes) -// countryPostal.regex == "" ? "" : countryPostal.regex -// } From 0ca98eb630b5ce2a15622cc79aded583423d2dda Mon Sep 17 00:00:00 2001 From: ChiragKV-Juspay Date: Fri, 20 Dec 2024 14:59:46 +0530 Subject: [PATCH 5/5] refactor: renamed cardNumber function --- src/components/elements/CardElement.res | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/elements/CardElement.res b/src/components/elements/CardElement.res index 4a723b0e..c9ec0985 100644 --- a/src/components/elements/CardElement.res +++ b/src/components/elements/CardElement.res @@ -58,7 +58,7 @@ let make = ( expireRef: React.ref>, ) => { let cardBrand = getCardBrand(text) - let num = formatCardNumber(text, cardType(cardBrand)) + let num = formatCardNumber(text, getCardType(cardBrand)) let isthisValid = cardValid(num, cardBrand) setCardData(prev => {...prev, cardNumber: num, isCardNumberValid: Some(isthisValid)}) @@ -115,7 +115,7 @@ let make = ( cvvRef: React.ref>, ) => { let cardBrand = getCardBrand(pan) - let cardNumber = formatCardNumber(pan, cardType(cardBrand)) + let cardNumber = formatCardNumber(pan, getCardType(cardBrand)) let isCardValid = cardValid(cardNumber, cardBrand) let expireDate = formatCardExpiryNumber(expiry) let isExpiryValid = checkCardExpiry(expireDate)