diff --git a/public/icons/orca.svg b/public/icons/orca.svg index 5cb955e11..e57670093 100644 --- a/public/icons/orca.svg +++ b/public/icons/orca.svg @@ -2543,4 +2543,8 @@ License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL + + + + diff --git a/src/Components/DynamicFields.res b/src/Components/DynamicFields.res index 60471082b..0d01e58d8 100644 --- a/src/Components/DynamicFields.res +++ b/src/Components/DynamicFields.res @@ -458,6 +458,7 @@ let make = ( | CryptoCurrencyNetworks => | DateOfBirth => + | VpaId => | Email | InfoElement | Country @@ -765,6 +766,7 @@ let make = ( | CryptoCurrencyNetworks | DateOfBirth | PhoneCountryCode + | VpaId | None => React.null }} diff --git a/src/Components/VpaIdPaymentInput.res b/src/Components/VpaIdPaymentInput.res new file mode 100644 index 000000000..275ed7dc5 --- /dev/null +++ b/src/Components/VpaIdPaymentInput.res @@ -0,0 +1,61 @@ +open RecoilAtoms +open Utils + +@react.component +let make = (~paymentType) => { + let {localeString} = Recoil.useRecoilValueFromAtom(configAtom) + let loggerState = Recoil.useRecoilValueFromAtom(loggerAtom) + let (vpaId, setVpaId) = Recoil.useLoggedRecoilState(userVpaId, "vpaId", loggerState) + + let vpaIdRef = React.useRef(Nullable.null) + + let changeVpaId = ev => { + let val: string = ReactEvent.Form.target(ev)["value"] + setVpaId(prev => { + value: val, + isValid: val->isVpaIdValid, + errorString: val->isVpaIdValid->Option.getOr(false) ? "" : prev.errorString, + }) + } + let onBlur = ev => { + let val = ReactEvent.Focus.target(ev)["value"] + let isValid = val->isVpaIdValid + let errorString = switch isValid { + | Some(val) => val ? "" : localeString.vpaIdInvalidText + | None => "" + } + + setVpaId(prev => { + ...prev, + isValid, + errorString, + }) + } + + let submitCallback = React.useCallback((ev: Window.event) => { + let json = ev.data->JSON.parseExn + let confirm = json->getDictFromJson->ConfirmType.itemToObjMapper + if confirm.doSubmit { + if vpaId.value == "" { + setVpaId(prev => { + ...prev, + errorString: localeString.vpaIdEmptyText, + }) + } + } + }, [vpaId]) + useSubmitPaymentData(submitCallback) + + +} diff --git a/src/LocaleStrings/ArabicLocale.res b/src/LocaleStrings/ArabicLocale.res index 9700c718d..e86f2914f 100644 --- a/src/LocaleStrings/ArabicLocale.res +++ b/src/LocaleStrings/ArabicLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `شبكات العملات`, expiryPlaceholder: `MM / YY`, dateOfBirth: `تاريخ الميلاد`, + vpaIdLabel: `معرف VPA`, + vpaIdEmptyText: `لا يمكن أن يكون معرف Vpa فارغًا`, + vpaIdInvalidText: `معرف Vpa غير صالح`, } diff --git a/src/LocaleStrings/CatalanLocale.res b/src/LocaleStrings/CatalanLocale.res index a5ff0d1c3..d5e3e21b1 100644 --- a/src/LocaleStrings/CatalanLocale.res +++ b/src/LocaleStrings/CatalanLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Xarxes de Monedes`, expiryPlaceholder: `MM / AA`, dateOfBirth: `Data de naixement`, + vpaIdLabel: `Vpa Id`, + vpaIdEmptyText: `L'identificador de Vpa no pot estar buit`, + vpaIdInvalidText: `Identificador de VPA no vàlid`, } diff --git a/src/LocaleStrings/DeutschLocale.res b/src/LocaleStrings/DeutschLocale.res index b3dbf8d85..aa3bf7b45 100644 --- a/src/LocaleStrings/DeutschLocale.res +++ b/src/LocaleStrings/DeutschLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Währungsnetzwerke`, expiryPlaceholder: `MM / JJ`, dateOfBirth: `Geburtsdatum`, + vpaIdLabel: `Vpa-ID`, + vpaIdEmptyText: `Die VPA-ID darf nicht leer sein`, + vpaIdInvalidText: `Ungültige VPA-ID`, } diff --git a/src/LocaleStrings/DutchLocale.res b/src/LocaleStrings/DutchLocale.res index 2021c3bca..44b55ea73 100644 --- a/src/LocaleStrings/DutchLocale.res +++ b/src/LocaleStrings/DutchLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Valutanetwerken`, expiryPlaceholder: `MM / JJ`, dateOfBirth: `Geboortedatum`, + vpaIdLabel: `Vpa-id`, + vpaIdEmptyText: `Vpa-ID mag niet leeg zijn`, + vpaIdInvalidText: `Ongeldige Vpa-ID`, } diff --git a/src/LocaleStrings/EnglishGBLocale.res b/src/LocaleStrings/EnglishGBLocale.res index fc7dae731..38f9b0d91 100644 --- a/src/LocaleStrings/EnglishGBLocale.res +++ b/src/LocaleStrings/EnglishGBLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Currency Networks`, expiryPlaceholder: `MM / YY`, dateOfBirth: `Date of Birth`, + vpaIdLabel: `Vpa Id`, + vpaIdEmptyText: `Vpa Id cannot be empty`, + vpaIdInvalidText: `Invalid Vpa Id address`, } diff --git a/src/LocaleStrings/EnglishLocale.res b/src/LocaleStrings/EnglishLocale.res index 71bd100a7..2ada38ccb 100644 --- a/src/LocaleStrings/EnglishLocale.res +++ b/src/LocaleStrings/EnglishLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Currency Networks`, expiryPlaceholder: `MM / YY`, dateOfBirth: `Date of Birth`, + vpaIdLabel: "Vpa Id", + vpaIdEmptyText: "Vpa Id cannot be empty", + vpaIdInvalidText: "Invalid Vpa Id address", } diff --git a/src/LocaleStrings/FrenchBelgiumLocale.res b/src/LocaleStrings/FrenchBelgiumLocale.res index 1d84d2d1b..50a979872 100644 --- a/src/LocaleStrings/FrenchBelgiumLocale.res +++ b/src/LocaleStrings/FrenchBelgiumLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Réseaux Monétaires`, expiryPlaceholder: `MM / AA`, dateOfBirth: `Date de naissance`, + vpaIdLabel: `Identifiant Vpa`, + vpaIdEmptyText: `L'identifiant Vpa ne peut pas être vide`, + vpaIdInvalidText: `Identifiant Vpa invalide`, } diff --git a/src/LocaleStrings/FrenchLocale.res b/src/LocaleStrings/FrenchLocale.res index cacfe3a13..6f477a411 100644 --- a/src/LocaleStrings/FrenchLocale.res +++ b/src/LocaleStrings/FrenchLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Réseaux Monétaires`, expiryPlaceholder: `MM / AA`, dateOfBirth: `Date de naissance`, + vpaIdLabel: `Identifiant Vpa`, + vpaIdEmptyText: `L'identifiant Vpa ne peut pas être vide`, + vpaIdInvalidText: `Identifiant Vpa invalide`, } diff --git a/src/LocaleStrings/HebrewLocale.res b/src/LocaleStrings/HebrewLocale.res index e6f2c94ac..a47571807 100644 --- a/src/LocaleStrings/HebrewLocale.res +++ b/src/LocaleStrings/HebrewLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `רשתות מטבעות`, expiryPlaceholder: `MM / YY`, dateOfBirth: `תאריך לידה`, + vpaIdLabel: `מזהה VPA`, + vpaIdEmptyText: `מזהה VPA לא יכול להיות ריק`, + vpaIdInvalidText: `מזהה VPA לא חוקי`, } diff --git a/src/LocaleStrings/ItalianLocale.res b/src/LocaleStrings/ItalianLocale.res index 7f71fcd15..b0cd1a52a 100644 --- a/src/LocaleStrings/ItalianLocale.res +++ b/src/LocaleStrings/ItalianLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Reti Valutarie`, expiryPlaceholder: `MM / AA`, dateOfBirth: `Data di nascita`, + vpaIdLabel: `Codice Vpa`, + vpaIdEmptyText: `L'ID Vpa non può essere vuoto`, + vpaIdInvalidText: `ID Vpa non valido`, } diff --git a/src/LocaleStrings/JapaneseLocale.res b/src/LocaleStrings/JapaneseLocale.res index 6c6bb2c97..e6ef52df8 100644 --- a/src/LocaleStrings/JapaneseLocale.res +++ b/src/LocaleStrings/JapaneseLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `通貨ネットワーク`, expiryPlaceholder: `MM / YY`, dateOfBirth: `生年月日`, + vpaIdLabel: `VPA ID`, + vpaIdEmptyText: `VPA ID を空にすることはできません`, + vpaIdInvalidText: `無効な VPA ID`, } diff --git a/src/LocaleStrings/LocaleStringTypes.res b/src/LocaleStrings/LocaleStringTypes.res index 7a9b90a2f..02959934b 100644 --- a/src/LocaleStrings/LocaleStringTypes.res +++ b/src/LocaleStrings/LocaleStringTypes.res @@ -76,4 +76,7 @@ type localeStrings = { currencyNetwork: string, expiryPlaceholder: string, dateOfBirth: string, + vpaIdLabel: string, + vpaIdEmptyText: string, + vpaIdInvalidText: string, } diff --git a/src/LocaleStrings/PolishLocale.res b/src/LocaleStrings/PolishLocale.res index 48d549f89..39265917d 100644 --- a/src/LocaleStrings/PolishLocale.res +++ b/src/LocaleStrings/PolishLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Sieci Walutowe`, expiryPlaceholder: `MM / RR`, dateOfBirth: `Data urodzenia`, + vpaIdLabel: `Identyfikator Vpa`, + vpaIdEmptyText: `Identyfikator Vpa nie może być pusty`, + vpaIdInvalidText: `Nieprawidłowy identyfikator Vpa`, } diff --git a/src/LocaleStrings/PortugueseLocale.res b/src/LocaleStrings/PortugueseLocale.res index dea76434f..24f343b89 100644 --- a/src/LocaleStrings/PortugueseLocale.res +++ b/src/LocaleStrings/PortugueseLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Redes de Moeda`, expiryPlaceholder: `MM / AA`, dateOfBirth: `Data de nascimento`, + vpaIdLabel: `ID VPA`, + vpaIdEmptyText: `O ID Vpa não pode ficar vazio`, + vpaIdInvalidText: `ID Vpa inválido`, } diff --git a/src/LocaleStrings/RussianLocale.res b/src/LocaleStrings/RussianLocale.res index dd1d77c1d..5969a7ad4 100644 --- a/src/LocaleStrings/RussianLocale.res +++ b/src/LocaleStrings/RussianLocale.res @@ -89,4 +89,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Валютные сети`, expiryPlaceholder: `MM / ГГ`, dateOfBirth: `Дата рождения`, + vpaIdLabel: `Идентификатор ВПА`, + vpaIdEmptyText: `Идентификатор VPA не может быть пустым.`, + vpaIdInvalidText: `Неверный идентификатор VPA`, } diff --git a/src/LocaleStrings/SpanishLocale.res b/src/LocaleStrings/SpanishLocale.res index b94079bc0..8fd11f1be 100644 --- a/src/LocaleStrings/SpanishLocale.res +++ b/src/LocaleStrings/SpanishLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Redes de Divisas`, expiryPlaceholder: `MM / AA`, dateOfBirth: `Fecha de nacimiento`, + vpaIdLabel: `Identificación de Vpa`, + vpaIdEmptyText: `El ID de Vpa no puede estar vacío`, + vpaIdInvalidText: `ID de Vpa no válido`, } diff --git a/src/LocaleStrings/SwedishLocale.res b/src/LocaleStrings/SwedishLocale.res index 50f07e395..0cad17fc2 100644 --- a/src/LocaleStrings/SwedishLocale.res +++ b/src/LocaleStrings/SwedishLocale.res @@ -85,4 +85,7 @@ let localeStrings: LocaleStringTypes.localeStrings = { currencyNetwork: `Valutanätverk`, expiryPlaceholder: `MM / ÅÅ`, dateOfBirth: `Födelsedatum`, + vpaIdLabel: `Vpa-id`, + vpaIdEmptyText: `Vpa-id får inte vara tomt`, + vpaIdInvalidText: `Ogiltigt Vpa-ID`, } diff --git a/src/Payments/PaymentMethodsRecord.res b/src/Payments/PaymentMethodsRecord.res index 175032769..38aba1c0a 100644 --- a/src/Payments/PaymentMethodsRecord.res +++ b/src/Payments/PaymentMethodsRecord.res @@ -37,6 +37,7 @@ type paymentMethodsFields = | ShippingAddressCountry(array) | CryptoCurrencyNetworks | DateOfBirth + | VpaId let getPaymentMethodsFieldsOrder = paymentMethodField => { switch paymentMethodField { @@ -524,6 +525,13 @@ let paymentMethodsFields = [ displayName: "Mifinity", miniIcon: None, }, + { + paymentMethodName: "upi_collect", + fields: [InfoElement], + icon: Some(icon("bhim_upi", ~size=19)), + displayName: "UPI Collect", + miniIcon: None, + }, ] type required_fields = { @@ -560,6 +568,7 @@ let getPaymentMethodsFieldTypeFromString = (str, isBancontact) => { | ("user_crypto_currency_network", _) => CryptoCurrencyNetworks | ("user_date_of_birth", _) => DateOfBirth | ("user_phone_number_country_code", _) => PhoneCountryCode + | ("user_vpa_id", _) => VpaId | _ => None } } @@ -637,6 +646,7 @@ let dynamicFieldsEnabledPaymentMethods = [ "local_bank_transfer_transfer", "afterpay_clearpay", "mifinity", + "upi_collect", ] let getIsBillingField = requiredFieldType => { diff --git a/src/Utilities/DynamicFieldsUtils.res b/src/Utilities/DynamicFieldsUtils.res index ffeb3a9d6..16f5fe252 100644 --- a/src/Utilities/DynamicFieldsUtils.res +++ b/src/Utilities/DynamicFieldsUtils.res @@ -110,6 +110,7 @@ let useRequiredFieldsEmptyAndValid = ( ~cvcNumber, ) => { let email = Recoil.useRecoilValueFromAtom(userEmailAddress) + let vpaId = Recoil.useRecoilValueFromAtom(userVpaId) let fullName = Recoil.useRecoilValueFromAtom(userFullName) let billingName = Recoil.useRecoilValueFromAtom(userBillingName) let line1 = Recoil.useRecoilValueFromAtom(userAddressline1) @@ -165,6 +166,7 @@ let useRequiredFieldsEmptyAndValid = ( | Some(val) => val->Utils.checkIs18OrAbove | None => false } + | VpaId => vpaId.isValid->Option.getOr(false) | _ => true } }) @@ -225,6 +227,7 @@ let useRequiredFieldsEmptyAndValid = ( dateOfBirth, ( email, + vpaId, line2.value, selectedBank, phone.value, @@ -412,6 +415,7 @@ let useSetInitialRequiredFields = ( | ShippingAddressPincode | ShippingAddressState | ShippingAddressCountry(_) + | VpaId | None => () } }) @@ -430,6 +434,7 @@ let useRequiredFieldsBody = ( ~setRequiredFieldsBody, ) => { let email = Recoil.useRecoilValueFromAtom(userEmailAddress) + let vpaId = Recoil.useRecoilValueFromAtom(userVpaId) let fullName = Recoil.useRecoilValueFromAtom(userFullName) let billingName = Recoil.useRecoilValueFromAtom(userBillingName) let line1 = Recoil.useRecoilValueFromAtom(userAddressline1) @@ -488,6 +493,7 @@ let useRequiredFieldsBody = ( | None => "" } | CardCvc => cvcNumber + | VpaId => vpaId.value | StateAndCity | CountryAndPincode(_) | SpecialField(_) @@ -565,6 +571,7 @@ let useRequiredFieldsBody = ( }, ( fullName.value, email.value, + vpaId.value, line1.value, line2.value, city.value, @@ -596,7 +603,8 @@ let isFieldTypeToRenderOutsideBilling = (fieldType: PaymentMethodsRecord.payment | CardExpiryAndCvc | CryptoCurrencyNetworks | DateOfBirth - | Currency(_) => true + | Currency(_) + | VpaId => true | _ => false } } diff --git a/src/Utilities/RecoilAtoms.res b/src/Utilities/RecoilAtoms.res index 1e3dd1c7a..fbb1f79e9 100644 --- a/src/Utilities/RecoilAtoms.res +++ b/src/Utilities/RecoilAtoms.res @@ -63,6 +63,7 @@ let areRequiredFieldsValid = Recoil.atom("areRequiredFieldsValid", true) let areRequiredFieldsEmpty = Recoil.atom("areRequiredFieldsEmpty", false) let dateOfBirth = Recoil.atom("dateOfBirth", Nullable.null) let userBillingName = Recoil.atom("userBillingName", defaultFieldValues) +let userVpaId = Recoil.atom("userVpaId", defaultFieldValues) type areOneClickWalletsRendered = { isGooglePay: bool, diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res index ecaafd04f..318e7a6bd 100644 --- a/src/Utilities/Utils.res +++ b/src/Utilities/Utils.res @@ -393,6 +393,15 @@ let isEmailValid = email => { } } +let isVpaIdValid = vpaId => { + switch vpaId->String.match( + %re("/^[a-zA-Z0-9]([a-zA-Z0-9.-]{1,50})[a-zA-Z0-9]@[a-zA-Z0-9]{2,}$/"), + ) { + | Some(_match) => Some(true) + | None => vpaId->String.length > 0 ? Some(false) : None + } +} + let checkEmailValid = ( email: RecoilAtomTypes.field, fn: (RecoilAtomTypes.field => RecoilAtomTypes.field) => unit,