diff --git a/src/Components/DropdownField.res b/src/Components/DropdownField.res index 12bddfb52..6b8606898 100644 --- a/src/Components/DropdownField.res +++ b/src/Components/DropdownField.res @@ -53,6 +53,7 @@ let make = ( ~fontWeight=themeObj.fontWeightNormal, ~fontSize=themeObj.fontSizeLg, ~marginBottom="5px", + ~opacity="0.6", (), )}> {React.string(fieldName)} @@ -90,6 +91,7 @@ let make = ( ~fontSize={ inputFocused || value->Js.String2.length > 0 ? themeObj.fontSizeXs : "" }, + ~opacity="0.6", (), )}> {React.string(fieldName)} diff --git a/src/Components/DynamicFields.res b/src/Components/DynamicFields.res index 6bd8c5c81..ebb9c5dfd 100644 --- a/src/Components/DynamicFields.res +++ b/src/Components/DynamicFields.res @@ -18,6 +18,8 @@ let make = ( None }, [paymentMethodType]) + let {billingAddress} = Recoil.useRecoilValueFromAtom(optionAtom) + //<...>// let paymentMethodTypes = PaymentMethodsRecord.getPaymentMethodTypeFromList( @@ -26,29 +28,25 @@ let make = ( ~paymentMethodType, )->Belt.Option.getWithDefault(PaymentMethodsRecord.defaultPaymentMethodType) - let requiredFields = if paymentMethod === "card" { + let requiredFieldsWithBillingDetails = if paymentMethod === "card" { let creditPaymentMethodsRecord = PaymentMethodsRecord.getPaymentMethodTypeFromList( ~list, ~paymentMethod, ~paymentMethodType="credit", )->Belt.Option.getWithDefault(PaymentMethodsRecord.defaultPaymentMethodType) - paymentMethodTypes.required_fields - ->Utils.getDictFromJson - ->Js.Dict.entries - ->Js.Array2.concat( - creditPaymentMethodsRecord.required_fields->Utils.getDictFromJson->Js.Dict.entries, - ) - ->Js.Dict.fromArray - ->Js.Json.object_ + paymentMethodTypes.required_fields->Js.Array2.concat(creditPaymentMethodsRecord.required_fields) } else if ( PaymentMethodsRecord.dynamicFieldsEnabledPaymentMethods->Js.Array2.includes(paymentMethodType) ) { paymentMethodTypes.required_fields } else { - Js.Json.null + [] } + let requiredFields = + requiredFieldsWithBillingDetails->DynamicFieldsUtils.removeBillingDetailsIfUseBillingAddress + let isAllStoredCardsHaveName = React.useMemo1(() => { PaymentType.getIsAllStoredCardsHaveName(savedCards) }, [savedCards]) @@ -60,12 +58,9 @@ let make = ( requiredFields, ~isSavedCardFlow, ~isAllStoredCardsHaveName, - ~isBancontact, (), ) - ->Utils.removeDuplicate - ->Js.Array2.filter(item => item !== None) - ->PaymentUtils.updateDynamicFields() + ->DynamicFieldsUtils.updateDynamicFields() ->Belt.SortArray.stableSortBy(PaymentMethodsRecord.sortPaymentMethodFields) //<...>// @@ -73,9 +68,6 @@ let make = ( let logger = Recoil.useRecoilValueFromAtom(loggerAtom) - let setAreRequiredFieldsValid = Recoil.useSetRecoilState(areRequiredFieldsValid) - let setAreRequiredFieldsEmpty = Recoil.useSetRecoilState(areRequiredFieldsEmpty) - let (line1, setLine1) = Recoil.useLoggedRecoilState(userAddressline1, "line1", logger) let (line2, setLine2) = Recoil.useLoggedRecoilState(userAddressline2, "line2", logger) let (city, setCity) = Recoil.useLoggedRecoilState(userAddressCity, "city", logger) @@ -239,18 +231,15 @@ let make = ( ~cvcNumber, ) - let requiredFieldsType = - requiredFields - ->Utils.getDictFromJson - ->Js.Dict.values - ->Js.Array2.map(item => - item->Utils.getDictFromJson->PaymentMethodsRecord.getRequiredFieldsFromJson(isBancontact) - ) - - DynamicFieldsUtils.useSetInitialRequiredFields(~requiredFieldsType, ~paymentMethodType) + DynamicFieldsUtils.useSetInitialRequiredFields( + ~requiredFields={ + billingAddress.usePrefilledValues === Auto ? requiredFieldsWithBillingDetails : requiredFields + }, + ~paymentMethodType, + ) DynamicFieldsUtils.useRequiredFieldsBody( - ~requiredFieldsType, + ~requiredFields, ~paymentMethodType, ~cardNumber, ~cardExpiry, @@ -264,7 +253,7 @@ let make = ( let getCustomFieldName = (item: PaymentMethodsRecord.paymentMethodsFields) => { if ( - requiredFieldsType + requiredFields ->Js.Array2.filter(requiredFieldType => requiredFieldType.field_type === item && requiredFieldType.display_name === "card_holder_name" @@ -279,12 +268,12 @@ let make = ( let dynamicFieldsToRenderOutsideBilling = fieldsArr->Js.Array2.filter(field => - PaymentMethodsRecord.dynamicFieldsToRenderOutsideBilling->Js.Array2.includes(field) + field->DynamicFieldsUtils.isFieldTypeToRenderOutsideBilling ) let dynamicFieldsToRenderInsideBilling = fieldsArr->Js.Array2.filter(field => - !(PaymentMethodsRecord.dynamicFieldsToRenderOutsideBilling->Js.Array2.includes(field)) + !(field->DynamicFieldsUtils.isFieldTypeToRenderOutsideBilling) ) let isInfoElementPresent = dynamicFieldsToRenderInsideBilling->Js.Array2.includes(InfoElement) @@ -410,6 +399,15 @@ let make = ( placeholder="123" /> + | Currency(currencyArr) => + | Email | FullName | InfoElement @@ -427,8 +425,7 @@ let make = ( | BlikCode | SpecialField(_) | CountryAndPincode(_) - | AddressCountry(_) - | Currency(_) => React.null + | AddressCountry(_) => React.null }} }) @@ -596,15 +593,6 @@ let make = ( placeholder=localeString.postalCodeLabel /> | BlikCode => - | Currency(currencyArr) => - | Country => React.null }} diff --git a/src/Components/PaymentDropDownField.res b/src/Components/PaymentDropDownField.res index e5f5b75d1..dfdd5d3e4 100644 --- a/src/Components/PaymentDropDownField.res +++ b/src/Components/PaymentDropDownField.res @@ -77,6 +77,7 @@ let make = ( ~fontWeight=themeObj.fontWeightNormal, ~fontSize=themeObj.fontSizeLg, ~marginBottom="5px", + ~opacity="0.6", (), )}> {React.string(fieldName)} @@ -114,21 +115,7 @@ let make = ( ~fontSize={ inputFocused || value.value->Js.String2.length > 0 ? themeObj.fontSizeXs : "" }, - (), - )}> - {React.string(fieldName)} - - - -
Js.String2.length > 0 ? "" : themeObj.spacingUnit - }, - ~fontSize={ - inputFocused || value.value->Js.String2.length > 0 ? themeObj.fontSizeXs : "" - }, + ~opacity="0.6", (), )}> {React.string(fieldName)} diff --git a/src/Components/PaymentField.res b/src/Components/PaymentField.res index a6e961ad8..01d05ed90 100644 --- a/src/Components/PaymentField.res +++ b/src/Components/PaymentField.res @@ -84,6 +84,7 @@ let make = ( ~fontWeight=themeObj.fontWeightNormal, ~fontSize=themeObj.fontSizeLg, ~marginBottom="5px", + ~opacity="0.6", (), )}> {React.string(fieldName)} @@ -124,6 +125,7 @@ let make = ( ~fontSize={ inputFocused || value.value->Js.String2.length > 0 ? themeObj.fontSizeXs : "" }, + ~opacity="0.6", (), )}> {React.string(fieldName)} diff --git a/src/Components/PaymentInputField.res b/src/Components/PaymentInputField.res index 79886a31b..086e64bfa 100644 --- a/src/Components/PaymentInputField.res +++ b/src/Components/PaymentInputField.res @@ -83,6 +83,7 @@ let make = ( ~fontWeight=themeObj.fontWeightNormal, ~fontSize=themeObj.fontSizeLg, ~marginBottom="5px", + ~opacity="0.6", (), )}> {React.string(fieldName)} @@ -120,6 +121,7 @@ let make = ( inputFocused || value->Js.String2.length > 0 ? "" : themeObj.spacingUnit }, ~fontSize={inputFocused || value->Js.String2.length > 0 ? themeObj.fontSizeXs : ""}, + ~opacity="0.6", (), )}> {React.string(fieldName)} diff --git a/src/Components/SavedMethods.res b/src/Components/SavedMethods.res index ce33cab94..baeb2e53b 100644 --- a/src/Components/SavedMethods.res +++ b/src/Components/SavedMethods.res @@ -71,17 +71,15 @@ let make = ( }} - Js.Array.length !== 0}> - - +
- Js.Array.length !== 0}> - - +
diff --git a/src/Payments/PaymentMethodsRecord.res b/src/Payments/PaymentMethodsRecord.res index 5e56a5b7c..f0cd6a750 100644 --- a/src/Payments/PaymentMethodsRecord.res +++ b/src/Payments/PaymentMethodsRecord.res @@ -548,15 +548,6 @@ let getFieldType = (dict, isBancontact) => { } } -let getRequiredFieldsFromJson = (dict, isBancontact) => { - { - required_field: Utils.getString(dict, "required_field", ""), - display_name: Utils.getString(dict, "display_name", ""), - field_type: dict->getFieldType(isBancontact), - value: Utils.getString(dict, "value", ""), - } -} - let dynamicFieldsEnabledPaymentMethods = [ "crypto_currency", "debit", @@ -579,9 +570,8 @@ let getIsBillingField = requiredFieldType => { } } -let getIsAnyBillingDetailEmpty = (requiredFieldsValues: array, isBancontact) => { - requiredFieldsValues->Js.Array2.reduce((acc, item) => { - let requiredField = item->Utils.getDictFromJson->getRequiredFieldsFromJson(isBancontact) +let getIsAnyBillingDetailEmpty = (requiredFields: array) => { + requiredFields->Js.Array2.reduce((acc, requiredField) => { if getIsBillingField(requiredField.field_type) { requiredField.value === "" || acc } else { @@ -592,16 +582,13 @@ let getIsAnyBillingDetailEmpty = (requiredFieldsValues: array, isBanc let getPaymentMethodFields = ( paymentMethod, - requiredFields, + requiredFields: array, ~isSavedCardFlow=false, ~isAllStoredCardsHaveName=false, - ~isBancontact=false, (), ) => { - let requiredFieldsValues = requiredFields->Utils.getDictFromJson->Js.Dict.values - let isAnyBillingDetailEmpty = requiredFieldsValues->getIsAnyBillingDetailEmpty(isBancontact) - let requiredFieldsArr = requiredFieldsValues->Js.Array2.map(item => { - let requiredField = item->Utils.getDictFromJson->getRequiredFieldsFromJson(isBancontact) + let isAnyBillingDetailEmpty = requiredFields->getIsAnyBillingDetailEmpty + let requiredFieldsArr = requiredFields->Js.Array2.map(requiredField => { let isShowBillingField = getIsBillingField(requiredField.field_type) && isAnyBillingDetailEmpty if requiredField.value === "" || isShowBillingField { if ( @@ -677,7 +664,7 @@ type paymentMethodTypes = { bank_names: array, bank_debits_connectors: array, bank_transfers_connectors: array, - required_fields: Js.Json.t, + required_fields: array, surcharge_details: option, } @@ -712,7 +699,7 @@ let defaultPaymentMethodType = { bank_names: [], bank_debits_connectors: [], bank_transfers_connectors: [], - required_fields: Js.Json.null, + required_fields: [], surcharge_details: None, } @@ -835,22 +822,42 @@ let getAchConnectors = (dict, str) => { ->getStrArray("elligible_connectors") } +let getDynamicFieldsFromJsonDict = (dict, isBancontact) => { + let requiredFields = + Utils.getJsonFromDict(dict, "required_fields", Js.Json.null) + ->Utils.getDictFromJson + ->Js.Dict.values + + requiredFields->Js.Array2.map(requiredField => { + let requiredFieldsDict = requiredField->Utils.getDictFromJson + { + required_field: requiredFieldsDict->Utils.getString("required_field", ""), + display_name: requiredFieldsDict->Utils.getString("display_name", ""), + field_type: requiredFieldsDict->getFieldType(isBancontact), + value: requiredFieldsDict->Utils.getString("value", ""), + } + }) +} + let getPaymentMethodTypes = (dict, str) => { dict ->Js.Dict.get(str) ->Belt.Option.flatMap(Js.Json.decodeArray) ->Belt.Option.getWithDefault([]) ->Belt.Array.keepMap(Js.Json.decodeObject) - ->Js.Array2.map(json => { + ->Js.Array2.map(jsonDict => { + let paymentMethodType = getString(jsonDict, "payment_method_type", "") { - payment_method_type: getString(json, "payment_method_type", ""), - payment_experience: getPaymentExperience(json, "payment_experience"), - card_networks: getCardNetworks(json, "card_networks"), - bank_names: getBankNames(json, "bank_names"), - bank_debits_connectors: getAchConnectors(json, "bank_debit"), - bank_transfers_connectors: getAchConnectors(json, "bank_transfer"), - required_fields: Utils.getJsonFromDict(json, "required_fields", Js.Json.null), - surcharge_details: json->getSurchargeDetails, + payment_method_type: paymentMethodType, + payment_experience: getPaymentExperience(jsonDict, "payment_experience"), + card_networks: getCardNetworks(jsonDict, "card_networks"), + bank_names: getBankNames(jsonDict, "bank_names"), + bank_debits_connectors: getAchConnectors(jsonDict, "bank_debit"), + bank_transfers_connectors: getAchConnectors(jsonDict, "bank_transfer"), + required_fields: jsonDict->getDynamicFieldsFromJsonDict( + paymentMethodType === "bancontact_card", + ), + surcharge_details: jsonDict->getSurchargeDetails, } }) } @@ -922,7 +929,6 @@ let buildFromPaymentList = (plist: list) => { fields: getPaymentMethodFields( paymentMethodName, individualPaymentMethod.required_fields, - ~isBancontact=individualPaymentMethod.payment_method_type === "bancontact_card", (), ), paymentFlow: paymentExperience, @@ -955,15 +961,6 @@ let getPaymentMethodTypeFromList = (~list: list, ~paymentMethod, ~paymentMethodT }) } -let dynamicFieldsToRenderOutsideBilling = [ - CardNumber, - CardExpiryMonth, - CardExpiryYear, - CardExpiryMonthAndYear, - CardCvc, - CardExpiryAndCvc, -] - let getCardNetwork = (~paymentMethodType, ~cardBrand) => { paymentMethodType.card_networks ->Js.Array2.filter(cardNetwork => cardNetwork.card_network === cardBrand) diff --git a/src/Payments/PaymentMethodsWrapper.res b/src/Payments/PaymentMethodsWrapper.res index 234359494..2deb9ae76 100644 --- a/src/Payments/PaymentMethodsWrapper.res +++ b/src/Payments/PaymentMethodsWrapper.res @@ -116,15 +116,13 @@ let make = (
- Js.Array.length !== 0}> - - +
} diff --git a/src/Types/PaymentType.res b/src/Types/PaymentType.res index c32052bb6..a1fbe2f87 100644 --- a/src/Types/PaymentType.res +++ b/src/Types/PaymentType.res @@ -123,6 +123,12 @@ type customerMethods = { card: customerCard, } type savedCardsLoadState = LoadingSavedCards | LoadedSavedCards(array) | NoResult + +type billingAddress = { + isUseBillingAddress: bool, + usePrefilledValues: showType, +} + type options = { defaultValues: defaultValues, layout: layoutType, @@ -138,6 +144,7 @@ type options = { branding: showType, payButtonStyle: style, showCardFormByDefault: bool, + billingAddress: billingAddress, } let defaultCardDetails = { scheme: None, @@ -233,6 +240,10 @@ let defaultWallets = { googlePay: Auto, style: defaultStyle, } +let defaultBillingAddress = { + isUseBillingAddress: false, + usePrefilledValues: Auto, +} let defaultOptions = { defaultValues: defaultDefaultValues, business: defaultBusiness, @@ -248,6 +259,7 @@ let defaultOptions = { payButtonStyle: defaultStyle, customMethodNames: [], showCardFormByDefault: true, + billingAddress: defaultBillingAddress, } let getLayout = (str, logger) => { switch str { @@ -815,6 +827,31 @@ let getCustomMethodNames = (dict, str) => { }) } +let getBillingAddress = (dict, str, logger) => { + dict + ->Js.Dict.get(str) + ->Belt.Option.flatMap(Js.Json.decodeObject) + ->Belt.Option.map(json => { + unknownKeysWarning( + ["isUseBillingAddress", "usePrefilledValues"], + json, + "options.billingAddress", + ~logger, + ) + + { + isUseBillingAddress: getBoolWithWarning(json, "isUseBillingAddress", false, ~logger), + usePrefilledValues: getWarningString( + json, + "usePrefilledValues", + "auto", + ~logger, + )->getShowType("options.billingAddress.usePrefilledValues", logger), + } + }) + ->Belt.Option.getWithDefault(defaultBillingAddress) +} + let itemToObjMapper = (dict, logger) => { unknownKeysWarning( [ @@ -852,6 +889,7 @@ let itemToObjMapper = (dict, logger) => { customMethodNames: getCustomMethodNames(dict, "customMethodNames"), payButtonStyle: getStyle(dict, "payButtonStyle", logger), showCardFormByDefault: getBool(dict, "showCardFormByDefault", true), + billingAddress: getBillingAddress(dict, "billingAddress", logger), } } diff --git a/src/Utilities/DynamicFieldsUtils.res b/src/Utilities/DynamicFieldsUtils.res index 3e53dbb2a..e9897e405 100644 --- a/src/Utilities/DynamicFieldsUtils.res +++ b/src/Utilities/DynamicFieldsUtils.res @@ -1,3 +1,76 @@ +let getName = (item: PaymentMethodsRecord.required_fields, field: RecoilAtomTypes.field) => { + let fieldNameArr = field.value->Js.String2.split(" ") + let requiredFieldsArr = item.required_field->Js.String2.split(".") + switch requiredFieldsArr + ->Belt.Array.get(requiredFieldsArr->Belt.Array.length - 1) + ->Belt.Option.getWithDefault("") { + | "first_name" => fieldNameArr->Belt.Array.get(0)->Belt.Option.getWithDefault(field.value) + | "last_name" => fieldNameArr->Belt.Array.sliceToEnd(1)->Js.Array2.reduce((acc, item) => { + acc ++ item + }, "") + | _ => field.value + } +} + +let countryNames = Utils.getCountryNames(Country.country) + +let billingAddressFields: array = [ + AddressLine1, + AddressLine2, + AddressCity, + AddressState, + AddressCountry(countryNames), + AddressPincode, +] + +let isBillingAddressFieldType = (fieldType: PaymentMethodsRecord.paymentMethodsFields) => { + switch fieldType { + | AddressLine1 + | AddressLine2 + | AddressCity + | AddressState + | AddressCountry(_) + | AddressPincode => true + | _ => false + } +} + +let getBillingAddressPathFromFieldType = (fieldType: PaymentMethodsRecord.paymentMethodsFields) => { + switch fieldType { + | AddressLine1 => "billing.address.line1" + | AddressLine2 => "billing.address.line2" + | AddressCity => "billing.address.city" + | AddressState => "billing.address.state" + | AddressCountry(_) => "billing.address.country" + | AddressPincode => "billing.address.zip" + | _ => "" + } +} + +let removeBillingDetailsIfUseBillingAddress = ( + requiredFields: Js.Array2.t, +) => { + let {billingAddress} = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom) + + if billingAddress.isUseBillingAddress { + requiredFields->Js.Array2.filter(requiredField => { + !(requiredField.field_type->isBillingAddressFieldType) + }) + } else { + requiredFields + } +} + +let addBillingAddressIfUseBillingAddress = fieldsArr => { + let {billingAddress} = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom) + + if billingAddress.isUseBillingAddress { + fieldsArr->Js.Array2.concat(billingAddressFields) + } else { + fieldsArr + } +} + let useRequiredFieldsEmptyAndValid = ( ~fieldsArr: Js.Array2.t, ~countryNames, @@ -25,82 +98,86 @@ let useRequiredFieldsEmptyAndValid = ( let setAreRequiredFieldsValid = Recoil.useSetRecoilState(RecoilAtoms.areRequiredFieldsValid) let setAreRequiredFieldsEmpty = Recoil.useSetRecoilState(RecoilAtoms.areRequiredFieldsEmpty) + let fieldsArrWithBillingAddress = fieldsArr->addBillingAddressIfUseBillingAddress + React.useEffect7(() => { - let areRequiredFieldsValid = fieldsArr->Js.Array2.reduce((acc, paymentMethodFields) => { - acc && - switch paymentMethodFields { - | Email => email.isValid - | FullName => Some(fullName.value !== "") - | Country => Some(country !== "" || countryNames->Belt.Array.length === 0) - | AddressCountry(countryArr) => Some(country !== "" || countryArr->Belt.Array.length === 0) - | BillingName => Some(billingName.value !== "") - | AddressLine1 => Some(line1.value !== "") - | AddressLine2 => Some(line2.value !== "") - | Bank => Some(selectedBank !== "" || bankNames->Belt.Array.length === 0) - | PhoneNumber => Some(phone.value !== "") - | StateAndCity => Some(state.value !== "" && city.value !== "") - | CountryAndPincode(countryArr) => - Some( - (country !== "" || countryArr->Belt.Array.length === 0) && - postalCode.isValid->Belt.Option.getWithDefault(false), - ) - | AddressCity => Some(city.value !== "") - | AddressPincode => postalCode.isValid - | AddressState => Some(state.value !== "") - | BlikCode => Some(blikCode.value !== "") - | Currency(currencyArr) => Some(currency !== "" || currencyArr->Belt.Array.length === 0) - | CardNumber => isCardValid - | CardExpiryMonth - | CardExpiryYear - | CardExpiryMonthAndYear => isExpiryValid - | CardCvc => isCVCValid - | CardExpiryAndCvc => - Some( - isExpiryValid->Belt.Option.getWithDefault(false) && - isCVCValid->Belt.Option.getWithDefault(false), - ) - | _ => Some(true) - }->Belt.Option.getWithDefault(false) - }, true) + let areRequiredFieldsValid = + fieldsArrWithBillingAddress->Js.Array2.reduce((acc, paymentMethodFields) => { + acc && + switch paymentMethodFields { + | Email => email.isValid + | FullName => Some(fullName.value !== "") + | Country => Some(country !== "" || countryNames->Belt.Array.length === 0) + | AddressCountry(countryArr) => Some(country !== "" || countryArr->Belt.Array.length === 0) + | BillingName => Some(billingName.value !== "") + | AddressLine1 => Some(line1.value !== "") + | AddressLine2 => Some(line2.value !== "") + | Bank => Some(selectedBank !== "" || bankNames->Belt.Array.length === 0) + | PhoneNumber => Some(phone.value !== "") + | StateAndCity => Some(state.value !== "" && city.value !== "") + | CountryAndPincode(countryArr) => + Some( + (country !== "" || countryArr->Belt.Array.length === 0) && + postalCode.isValid->Belt.Option.getWithDefault(false), + ) + | AddressCity => Some(city.value !== "") + | AddressPincode => postalCode.isValid + | AddressState => Some(state.value !== "") + | BlikCode => Some(blikCode.value !== "") + | Currency(currencyArr) => Some(currency !== "" || currencyArr->Belt.Array.length === 0) + | CardNumber => isCardValid + | CardExpiryMonth + | CardExpiryYear + | CardExpiryMonthAndYear => isExpiryValid + | CardCvc => isCVCValid + | CardExpiryAndCvc => + Some( + isExpiryValid->Belt.Option.getWithDefault(false) && + isCVCValid->Belt.Option.getWithDefault(false), + ) + | _ => Some(true) + }->Belt.Option.getWithDefault(false) + }, true) setAreRequiredFieldsValid(._ => areRequiredFieldsValid) - let areRequiredFieldsEmpty = fieldsArr->Js.Array2.reduce((acc, paymentMethodFields) => { - acc || - switch paymentMethodFields { - | Email => email.value === "" - | FullName => fullName.value === "" - | Country => country === "" && countryNames->Belt.Array.length > 0 - | AddressCountry(countryArr) => country === "" && countryArr->Belt.Array.length > 0 - | BillingName => billingName.value === "" - | AddressLine1 => line1.value === "" - | AddressLine2 => line2.value === "" - | Bank => selectedBank === "" && bankNames->Belt.Array.length > 0 - | StateAndCity => city.value === "" || state.value === "" - | CountryAndPincode(countryArr) => - (country === "" && countryArr->Belt.Array.length > 0) || postalCode.value === "" - | PhoneNumber => phone.value === "" - | AddressCity => city.value === "" - | AddressPincode => postalCode.value === "" - | AddressState => state.value === "" - | BlikCode => blikCode.value === "" - | Currency(currencyArr) => currency === "" && currencyArr->Belt.Array.length > 0 - | CardNumber => cardNumber === "" - | CardExpiryMonth => - let (month, _) = CardUtils.getExpiryDates(cardExpiry) - month === "" - | CardExpiryYear => - let (_, year) = CardUtils.getExpiryDates(cardExpiry) - year === "" - | CardExpiryMonthAndYear => - let (month, year) = CardUtils.getExpiryDates(cardExpiry) - month === "" || year === "" - | CardCvc => cvcNumber === "" - | CardExpiryAndCvc => - let (month, year) = CardUtils.getExpiryDates(cardExpiry) - month === "" || year === "" || cvcNumber === "" - | _ => false - } - }, false) + let areRequiredFieldsEmpty = + fieldsArrWithBillingAddress->Js.Array2.reduce((acc, paymentMethodFields) => { + acc || + switch paymentMethodFields { + | Email => email.value === "" + | FullName => fullName.value === "" + | Country => country === "" && countryNames->Belt.Array.length > 0 + | AddressCountry(countryArr) => country === "" && countryArr->Belt.Array.length > 0 + | BillingName => billingName.value === "" + | AddressLine1 => line1.value === "" + | AddressLine2 => line2.value === "" + | Bank => selectedBank === "" && bankNames->Belt.Array.length > 0 + | StateAndCity => city.value === "" || state.value === "" + | CountryAndPincode(countryArr) => + (country === "" && countryArr->Belt.Array.length > 0) || postalCode.value === "" + | PhoneNumber => phone.value === "" + | AddressCity => city.value === "" + | AddressPincode => postalCode.value === "" + | AddressState => state.value === "" + | BlikCode => blikCode.value === "" + | Currency(currencyArr) => currency === "" && currencyArr->Belt.Array.length > 0 + | CardNumber => cardNumber === "" + | CardExpiryMonth => + let (month, _) = CardUtils.getExpiryDates(cardExpiry) + month === "" + | CardExpiryYear => + let (_, year) = CardUtils.getExpiryDates(cardExpiry) + year === "" + | CardExpiryMonthAndYear => + let (month, year) = CardUtils.getExpiryDates(cardExpiry) + month === "" || year === "" + | CardCvc => cvcNumber === "" + | CardExpiryAndCvc => + let (month, year) = CardUtils.getExpiryDates(cardExpiry) + month === "" || year === "" || cvcNumber === "" + | _ => false + } + }, false) setAreRequiredFieldsEmpty(._ => areRequiredFieldsEmpty) None }, ( @@ -116,7 +193,7 @@ let useRequiredFieldsEmptyAndValid = ( selectedBank, phone.value, city.value, - postalCode.value, + postalCode, state.value, blikCode.value, isCardValid, @@ -130,7 +207,7 @@ let useRequiredFieldsEmptyAndValid = ( } let useSetInitialRequiredFields = ( - ~requiredFieldsType: Js.Array2.t, + ~requiredFields: Js.Array2.t, ~paymentMethodType, ) => { let logger = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom) @@ -178,7 +255,7 @@ let useSetInitialRequiredFields = ( React.useEffect0(() => { let getNameValue = (item: PaymentMethodsRecord.required_fields) => { - requiredFieldsType + requiredFields ->Js.Array2.filter(requiredFields => requiredFields.field_type === item.field_type) ->Js.Array2.reduce((acc, item) => { let requiredFieldsArr = item.required_field->Js.String2.split(".") @@ -212,7 +289,7 @@ let useSetInitialRequiredFields = ( } } - requiredFieldsType->Js.Array2.forEach(requiredField => { + requiredFields->Js.Array2.forEach(requiredField => { let value = requiredField.value switch requiredField.field_type { | Email => { @@ -287,7 +364,7 @@ let useSetInitialRequiredFields = ( } let useRequiredFieldsBody = ( - ~requiredFieldsType: Js.Array2.t, + ~requiredFields: Js.Array2.t, ~paymentMethodType, ~cardNumber, ~cardExpiry, @@ -309,72 +386,71 @@ let useRequiredFieldsBody = ( let country = Recoil.useRecoilValueFromAtom(RecoilAtoms.userCountry) let selectedBank = Recoil.useRecoilValueFromAtom(RecoilAtoms.userBank) let currency = Recoil.useRecoilValueFromAtom(RecoilAtoms.userCurrency) + let {billingAddress} = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom) - React.useEffect1(() => { - let getName = (item: PaymentMethodsRecord.required_fields, field: RecoilAtomTypes.field) => { - let fieldNameArr = field.value->Js.String2.split(" ") - let requiredFieldsArr = item.required_field->Js.String2.split(".") - switch requiredFieldsArr - ->Belt.Array.get(requiredFieldsArr->Belt.Array.length - 1) - ->Belt.Option.getWithDefault("") { - | "first_name" => fieldNameArr->Belt.Array.get(0)->Belt.Option.getWithDefault(field.value) - | "last_name" => fieldNameArr->Belt.Array.sliceToEnd(1)->Js.Array2.reduce((acc, item) => { - acc ++ item - }, "") - | _ => field.value + let getFieldValueFromFieldType = (fieldType: PaymentMethodsRecord.paymentMethodsFields) => { + switch fieldType { + | Email => email.value + | AddressLine1 => line1.value + | AddressLine2 => line2.value + | AddressCity => city.value + | AddressPincode => postalCode.value + | AddressState => state.value + | BlikCode => blikCode.value + | PhoneNumber => phone.value + | Currency(_) => currency + | Country => country + | Bank => selectedBank + | AddressCountry(_) => { + let countryCode = + Country.getCountry(paymentMethodType) + ->Js.Array2.filter(item => item.countryName === country) + ->Belt.Array.get(0) + ->Belt.Option.getWithDefault(Country.defaultTimeZone) + countryCode.isoAlpha2 } + | CardNumber => cardNumber->CardUtils.clearSpaces + | CardExpiryMonth => + let (month, _) = CardUtils.getExpiryDates(cardExpiry) + month + | CardExpiryYear => + let (_, year) = CardUtils.getExpiryDates(cardExpiry) + year + | CardCvc => cvcNumber + | StateAndCity + | CountryAndPincode(_) + | SpecialField(_) + | InfoElement + | CardExpiryMonthAndYear + | CardExpiryAndCvc + | FullName + | BillingName + | None => "" + } + } + + let addBillingDetailsIfUseBillingAddress = requiredFieldsBody => { + if billingAddress.isUseBillingAddress { + billingAddressFields->Js.Array2.reduce((acc, item) => { + let value = item->getFieldValueFromFieldType + let path = item->getBillingAddressPathFromFieldType + acc->Js.Dict.set(path, value->Js.Json.string) + acc + }, requiredFieldsBody) + } else { + requiredFieldsBody } + } + React.useEffect1(() => { let requiredFieldsBody = - requiredFieldsType + requiredFields ->Js.Array2.filter(item => item.field_type !== None) ->Js.Array2.reduce((acc, item) => { let value = switch item.field_type { - | Email => email.value - | FullName => getName(item, fullName) - | AddressLine1 => line1.value - | AddressLine2 => line2.value - | AddressCity => city.value - | AddressPincode => postalCode.value - | AddressState => state.value - | BlikCode => blikCode.value - | PhoneNumber => phone.value - | Currency(_) => currency - | Country => country - | Bank => selectedBank | BillingName => getName(item, billingName) - | AddressCountry(_) => { - let countryCode = - Country.getCountry(paymentMethodType) - ->Js.Array2.filter(item => item.countryName === country) - ->Belt.Array.get(0) - ->Belt.Option.getWithDefault(Country.defaultTimeZone) - countryCode.isoAlpha2 - } - | CardNumber => cardNumber->CardUtils.clearSpaces - | CardExpiryMonth => - let (month, _) = CardUtils.getExpiryDates(cardExpiry) - month - | CardExpiryYear => - let (_, year) = CardUtils.getExpiryDates(cardExpiry) - year - | CardCvc => cvcNumber - | StateAndCity - | CountryAndPincode(_) - | SpecialField(_) - | InfoElement - | CardExpiryMonthAndYear - | CardExpiryAndCvc - | None => "" - } - switch item.field_type { - | StateAndCity => - acc->Js.Dict.set("billing.address.city", city.value->Js.Json.string) - acc->Js.Dict.set("billing.address.state", state.value->Js.Json.string) - | CountryAndPincode(_) => - acc->Js.Dict.set("billing.address.country", city.value->Js.Json.string) - acc->Js.Dict.set("billing.address.zip", postalCode.value->Js.Json.string) - | _ => () + | FullName => getName(item, fullName) + | _ => item.field_type->getFieldValueFromFieldType } if ( isSavedCardFlow && @@ -393,6 +469,7 @@ let useRequiredFieldsBody = ( } acc }, Js.Dict.empty()) + ->addBillingDetailsIfUseBillingAddress setRequiredFieldsBody(_ => requiredFieldsBody) None @@ -414,3 +491,117 @@ let useRequiredFieldsBody = ( cvcNumber, ]) } + +let isFieldTypeToRenderOutsideBilling = (fieldType: PaymentMethodsRecord.paymentMethodsFields) => { + switch fieldType { + | CardNumber + | CardExpiryMonth + | CardExpiryYear + | CardExpiryMonthAndYear + | CardCvc + | CardExpiryAndCvc + | Currency(_) => true + | _ => false + } +} + +let combineStateAndCity = arr => { + open PaymentMethodsRecord + let hasStateAndCity = + arr->Js.Array2.includes(AddressState) && arr->Js.Array2.includes(AddressCity) + if hasStateAndCity { + arr->Js.Array2.push(StateAndCity)->ignore + arr->Js.Array2.filter(item => + switch item { + | AddressCity + | AddressState => false + | _ => true + } + ) + } else { + arr + } +} + +let combineCountryAndPostal = arr => { + open PaymentMethodsRecord + let hasCountryAndPostal = + arr + ->Js.Array2.filter(item => + switch item { + | AddressCountry(_) => true + | AddressPincode => true + | _ => false + } + ) + ->Js.Array2.length == 2 + + let options = arr->Js.Array2.reduce((acc, item) => { + acc->Js.Array2.concat( + switch item { + | AddressCountry(val) => val + | _ => [""] + }, + ) + }, [""]) + + if hasCountryAndPostal { + arr->Js.Array2.push(CountryAndPincode(options))->ignore + arr->Js.Array2.filter(item => + switch item { + | AddressPincode + | AddressCountry(_) => false + | _ => true + } + ) + } else { + arr + } +} + +let combineCardExpiryMonthAndYear = arr => { + open PaymentMethodsRecord + let hasCardExpiryMonthAndYear = + arr->Js.Array2.includes(CardExpiryMonth) && arr->Js.Array2.includes(CardExpiryYear) + if hasCardExpiryMonthAndYear { + arr->Js.Array2.push(CardExpiryMonthAndYear)->ignore + arr->Js.Array2.filter(item => + switch item { + | CardExpiryMonth + | CardExpiryYear => false + | _ => true + } + ) + } else { + arr + } +} + +let combineCardExpiryAndCvc = arr => { + open PaymentMethodsRecord + let hasCardExpiryAndCvc = + arr->Js.Array2.includes(CardExpiryMonthAndYear) && arr->Js.Array2.includes(CardCvc) + if hasCardExpiryAndCvc { + arr->Js.Array2.push(CardExpiryAndCvc)->ignore + arr->Js.Array2.filter(item => + switch item { + | CardExpiryMonthAndYear + | CardCvc => false + | _ => true + } + ) + } else { + arr + } +} + +let updateDynamicFields = (arr: Js.Array2.t, ()) => { + arr + ->Utils.removeDuplicate + ->Js.Array2.filter(item => item !== None) + ->addBillingAddressIfUseBillingAddress + ->combineStateAndCity + ->combineCountryAndPostal + ->combineCardExpiryMonthAndYear + ->combineCardExpiryAndCvc +} diff --git a/src/Utilities/PaymentUtils.res b/src/Utilities/PaymentUtils.res index 24170291c..456781432 100644 --- a/src/Utilities/PaymentUtils.res +++ b/src/Utilities/PaymentUtils.res @@ -230,101 +230,3 @@ let getDisplayNameAndIcon = ( | None => (defaultName, defaultIcon) } } - -let combineStateAndCity = arr => { - open PaymentMethodsRecord - let hasStateAndCity = - arr->Js.Array2.includes(AddressState) && arr->Js.Array2.includes(AddressCity) - if hasStateAndCity { - arr->Js.Array2.push(StateAndCity)->ignore - arr->Js.Array2.filter(item => - switch item { - | AddressCity - | AddressState => false - | _ => true - } - ) - } else { - arr - } -} - -let combineCountryAndPostal = arr => { - open PaymentMethodsRecord - let hasCountryAndPostal = - arr - ->Js.Array2.filter(item => - switch item { - | AddressCountry(_) => true - | AddressPincode => true - | _ => false - } - ) - ->Js.Array2.length == 2 - - let options = arr->Js.Array2.reduce((acc, item) => { - acc->Js.Array2.concat( - switch item { - | AddressCountry(val) => val - | _ => [""] - }, - ) - }, [""]) - - if hasCountryAndPostal { - arr->Js.Array2.push(CountryAndPincode(options))->ignore - arr->Js.Array2.filter(item => - switch item { - | AddressPincode - | AddressCountry(_) => false - | _ => true - } - ) - } else { - arr - } -} - -let combineCardExpiryMonthAndYear = arr => { - open PaymentMethodsRecord - let hasCardExpiryMonthAndYear = - arr->Js.Array2.includes(CardExpiryMonth) && arr->Js.Array2.includes(CardExpiryYear) - if hasCardExpiryMonthAndYear { - arr->Js.Array2.push(CardExpiryMonthAndYear)->ignore - arr->Js.Array2.filter(item => - switch item { - | CardExpiryMonth - | CardExpiryYear => false - | _ => true - } - ) - } else { - arr - } -} - -let combineCardExpiryAndCvc = arr => { - open PaymentMethodsRecord - let hasCardExpiryAndCvc = - arr->Js.Array2.includes(CardExpiryMonthAndYear) && arr->Js.Array2.includes(CardCvc) - if hasCardExpiryAndCvc { - arr->Js.Array2.push(CardExpiryAndCvc)->ignore - arr->Js.Array2.filter(item => - switch item { - | CardExpiryMonthAndYear - | CardCvc => false - | _ => true - } - ) - } else { - arr - } -} - -let updateDynamicFields = (arr: Js.Array2.t, ()) => { - arr - ->combineStateAndCity - ->combineCountryAndPostal - ->combineCardExpiryMonthAndYear - ->combineCardExpiryAndCvc -}