diff --git a/src/Components/BillingNamePaymentInput.res b/src/Components/BillingNamePaymentInput.res
new file mode 100644
index 000000000..c29b23b13
--- /dev/null
+++ b/src/Components/BillingNamePaymentInput.res
@@ -0,0 +1,59 @@
+open RecoilAtoms
+open PaymentType
+open Utils
+
+@react.component
+let make = (~paymentType, ~customFieldName=None) => {
+ let {localeString} = Recoil.useRecoilValueFromAtom(configAtom)
+ let {fields} = Recoil.useRecoilValueFromAtom(optionAtom)
+ let loggerState = Recoil.useRecoilValueFromAtom(loggerAtom)
+
+ let (billingName, setBillingName) = Recoil.useLoggedRecoilState(
+ userBillingName,
+ "billingName",
+ loggerState,
+ )
+
+ let showDetails = getShowDetails(~billingDetails=fields.billingDetails, ~logger=loggerState)
+
+ let changeName = ev => {
+ let val: string = ReactEvent.Form.target(ev)["value"]
+ setBillingName(.prev => {
+ ...prev,
+ value: val,
+ errorString: "",
+ })
+ }
+ let (placeholder, fieldName) = switch customFieldName {
+ | Some(val) => (val, val)
+ | None => (localeString.billingNamePlaceholder, localeString.billingNameLabel)
+ }
+ let nameRef = React.useRef(Js.Nullable.null)
+
+ let submitCallback = React.useCallback1((ev: Window.event) => {
+ let json = ev.data->Js.Json.parseExn
+ let confirm = json->getDictFromJson->ConfirmType.itemToObjMapper
+ if confirm.doSubmit {
+ if billingName.value == "" {
+ setBillingName(.prev => {
+ ...prev,
+ errorString: `Please provide your ${fieldName}`,
+ })
+ }
+ }
+ }, [billingName])
+ submitPaymentData(submitCallback)
+
+
+
+
+}
diff --git a/src/Components/DynamicFields.res b/src/Components/DynamicFields.res
new file mode 100644
index 000000000..93948148e
--- /dev/null
+++ b/src/Components/DynamicFields.res
@@ -0,0 +1,450 @@
+open RecoilAtoms
+@react.component
+let make = (~paymentType, ~list, ~paymentMethod, ~paymentMethodType, ~setRequiredFieldsBody) => {
+ //<...>//
+ let paymentMethodTypes =
+ PaymentMethodsRecord.getPaymentMethodTypeFromList(
+ ~list,
+ ~paymentMethod,
+ ~paymentMethodType,
+ )->Belt.Option.getWithDefault(PaymentMethodsRecord.defaultPaymentMethodType)
+
+ let requiredFields = 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_
+ } else {
+ paymentMethodTypes.required_fields
+ }
+
+ //<...>//
+ let fieldsArr =
+ PaymentMethodsRecord.getPaymentMethodFields(paymentMethodType, requiredFields)
+ ->Utils.removeDuplicate
+ ->Js.Array2.filter(item => item !== None)
+ //<...>//
+
+ let {config, themeObj, localeString} = Recoil.useRecoilValueFromAtom(configAtom)
+
+ let logger = Recoil.useRecoilValueFromAtom(loggerAtom)
+
+ let setAreRequiredFieldsValid = Recoil.useSetRecoilState(areRequiredFieldsValid)
+ let setAreRequiredFieldsEmpty = Recoil.useSetRecoilState(areRequiredFieldsEmpty)
+
+ let (email, setEmail) = Recoil.useLoggedRecoilState(userEmailAddress, "email", logger)
+ let (line1, setLine1) = Recoil.useLoggedRecoilState(userAddressline1, "line1", logger)
+ let (line2, setLine2) = Recoil.useLoggedRecoilState(userAddressline1, "line2", logger)
+ let (city, setCity) = Recoil.useLoggedRecoilState(userAddressline1, "city", logger)
+ let (state, setState) = Recoil.useLoggedRecoilState(userAddressState, "state", logger)
+ let (postalCode, setPostalCode) = Recoil.useLoggedRecoilState(
+ userAddressPincode,
+ "postal_code",
+ logger,
+ )
+ let (postalCodes, setPostalCodes) = React.useState(_ => [PostalCodeType.defaultPostalCode])
+ let (fullName, setFullName) = Recoil.useLoggedRecoilState(userFullName, "fullName", logger)
+ let (blikCode, setBlikCode) = Recoil.useLoggedRecoilState(userBlikCode, "blikCode", logger)
+ let (phone, _) = Recoil.useLoggedRecoilState(userPhoneNumber, "phone", logger)
+ let (currency, setCurrency) = Recoil.useLoggedRecoilState(userCurrency, "currency", logger)
+ let (billingName, setBillingName) = Recoil.useLoggedRecoilState(
+ userBillingName,
+ "billingName",
+ logger,
+ )
+ let line1Ref = React.useRef(Js.Nullable.null)
+ let line2Ref = React.useRef(Js.Nullable.null)
+ let cityRef = React.useRef(Js.Nullable.null)
+ let postalRef = React.useRef(Js.Nullable.null)
+ let (selectedBank, setSelectedBank) = Recoil.useRecoilState(userBank)
+ let (country, setCountry) = Recoil.useRecoilState(userCountry)
+
+ let (stateJson, setStatesJson) = React.useState(_ => None)
+
+ let bankNames =
+ Bank.getBanks(paymentMethodType)->Utils.getBankNames(paymentMethodTypes.bank_names)
+ let countryNames = Utils.getCountryNames(Country.getCountry(paymentMethodType))
+
+ let setCurrency = val => {
+ setCurrency(. val)
+ }
+ let setSelectedBank = val => {
+ setSelectedBank(. val)
+ }
+ let setCountry = val => {
+ setCountry(. val)
+ }
+
+ React.useEffect0(() => {
+ let clientTimeZone = Utils.dateTimeFormat(.).resolvedOptions(.).timeZone
+ let clientCountry = Utils.getClientCountry(clientTimeZone)
+ setCountry(_ => clientCountry.countryName)
+ let bank = bankNames->Belt.Array.get(0)->Belt.Option.getWithDefault("")
+ setSelectedBank(_ => bank)
+ None
+ })
+
+ React.useEffect0(() => {
+ open Promise
+ // Dynamically import/download Postal codes and states JSON
+ PostalCodeType.importPostalCode("./../PostalCodes.bs.js")
+ ->then(res => {
+ setPostalCodes(_ => res.default)
+ resolve()
+ })
+ ->catch(_ => {
+ setPostalCodes(_ => [PostalCodeType.defaultPostalCode])
+ resolve()
+ })
+ ->ignore
+ AddressPaymentInput.importStates("./../States.json")
+ ->then(res => {
+ setStatesJson(_ => Some(res.states))
+ resolve()
+ })
+ ->catch(_ => {
+ setStatesJson(_ => None)
+ resolve()
+ })
+ ->ignore
+
+ None
+ })
+
+ let regex = CardUtils.postalRegex(
+ postalCodes,
+ ~country={Utils.getCountryCode(country).isoAlpha2},
+ (),
+ )
+
+ let onPostalChange = ev => {
+ let val = ReactEvent.Form.target(ev)["value"]
+
+ setPostalCode(.prev => {
+ ...prev,
+ value: val,
+ errorString: "",
+ })
+ if regex !== "" && Js.Re.test_(regex->Js.Re.fromString, val) {
+ CardUtils.blurRef(postalRef)
+ }
+ }
+
+ let onPostalBlur = ev => {
+ let val = ReactEvent.Focus.target(ev)["value"]
+ if regex !== "" && Js.Re.test_(regex->Js.Re.fromString, val) && val !== "" {
+ setPostalCode(.prev => {
+ ...prev,
+ isValid: Some(true),
+ errorString: "",
+ })
+ } else if regex !== "" && !Js.Re.test_(regex->Js.Re.fromString, val) && val !== "" {
+ setPostalCode(.prev => {
+ ...prev,
+ isValid: Some(false),
+ errorString: "Invalid postal code",
+ })
+ }
+ }
+
+ React.useEffect7(() => {
+ let areRequiredFieldsValid = fieldsArr->Js.Array2.reduce((acc, paymentMethodFields) => {
+ acc &&
+ switch paymentMethodFields {
+ | Email => email.isValid
+ | FullName => Some(fullName.value !== "")
+ | Country => Some(country !== "")
+ | BillingName => Some(billingName.value !== "")
+ | AddressLine1 => Some(line1.value !== "")
+ | AddressLine2 => Some(line2.value !== "")
+ | _ => 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 === ""
+ | BillingName => billingName.value === ""
+ | AddressLine1 => line1.value === ""
+ | AddressLine2 => line2.value === ""
+ | _ => false
+ }
+ }, false)
+ setAreRequiredFieldsEmpty(._ => areRequiredFieldsEmpty)
+ None
+ }, (fieldsArr, email, fullName, country, billingName, line1, line2))
+
+ let requiredFieldsType =
+ requiredFields
+ ->Utils.getDictFromJson
+ ->Js.Dict.values
+ ->Js.Array2.map(item =>
+ item->Utils.getDictFromJson->PaymentMethodsRecord.getRequiredFieldsFromJson
+ )
+
+ React.useEffect0(() => {
+ let setFields = (
+ setMethod: (. RecoilAtomTypes.field => RecoilAtomTypes.field) => unit,
+ field: RecoilAtomTypes.field,
+ fieldValue,
+ ) => {
+ field.value === ""
+ ? setMethod(.prev => {
+ ...prev,
+ value: fieldValue,
+ })
+ : ()
+ }
+
+ requiredFieldsType->Js.Array2.forEach(requiredField => {
+ let value = requiredField.value
+ switch requiredField.field_type {
+ | Email => {
+ setFields(setEmail, email, value)
+ let newEmail: RecoilAtomTypes.field = {
+ value: value,
+ isValid: None,
+ errorString: "",
+ }
+ Utils.checkEmailValid(newEmail, setEmail)
+ }
+ | FullName => setFields(setFullName, fullName, value)
+ | AddressLine1 => setFields(setLine1, line1, value)
+ | AddressLine2 => setFields(setLine2, line2, value)
+ | BlikCode => setFields(setBlikCode, blikCode, value)
+ | BillingName => setFields(setBillingName, billingName, value)
+ | AddressCountry(_) => {
+ let countryCode =
+ Country.getCountry(paymentMethodType)
+ ->Js.Array2.filter(item => item.isoAlpha2 === value)
+ ->Belt.Array.get(0)
+ ->Belt.Option.getWithDefault(Country.defaultTimeZone)
+ setCountry(_ => countryCode.countryName)
+ }
+ | _ => ()
+ }
+ })
+ None
+ })
+
+ 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 requiredFieldsBody =
+ requiredFieldsType
+ ->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
+ | 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
+ }
+ | _ => ""
+ }
+ acc->Js.Dict.set(item.required_field, value->Js.Json.string)
+ acc
+ }, Js.Dict.empty())
+
+ setRequiredFieldsBody(_ => requiredFieldsBody)
+ None
+ }, [
+ fullName.value,
+ email.value,
+ line1.value,
+ blikCode.value,
+ phone.value,
+ currency,
+ billingName.value,
+ country,
+ ])
+
+ let bottomElement =
+
+
+ {fieldsArr
+ ->Js.Array2.mapi((item, index) => {
+
Js.Int.toString}
+ className="flex flex-col w-full place-content-between"
+ style={ReactDOMStyle.make(
+ ~marginTop=index !== 0 || paymentMethod === "card" ? themeObj.spacingGridColumn : "",
+ ~gridColumnGap=themeObj.spacingGridRow,
+ (),
+ )}>
+ {switch item {
+ | FullName =>
+ | BillingName =>
+ | Email =>
+ | PhoneNumber =>
+ | AddressLine1 =>
+
{
+ setLine1(.prev => {
+ ...prev,
+ value: ReactEvent.Form.target(ev)["value"],
+ })
+ }}
+ paymentType
+ type_="text"
+ name="line1"
+ inputRef=line1Ref
+ placeholder=localeString.line1Placeholder
+ />
+ | AddressLine2 =>
+ {
+ setLine2(.prev => {
+ ...prev,
+ value: ReactEvent.Form.target(ev)["value"],
+ })
+ }}
+ paymentType
+ type_="text"
+ name="line2"
+ inputRef=line2Ref
+ placeholder=localeString.line2Placeholder
+ />
+ | AddressCity =>
+ {
+ setCity(.prev => {
+ ...prev,
+ value: ReactEvent.Form.target(ev)["value"],
+ })
+ }}
+ paymentType
+ type_="text"
+ name="city"
+ inputRef=cityRef
+ placeholder=localeString.cityLabel
+ />
+ | AddressState =>
+ switch stateJson {
+ | Some(options) =>
+ Utils.getStateNames({
+ value: country,
+ isValid: None,
+ errorString: "",
+ })}
+ defaultSelected=false
+ />
+ | None => React.null
+ }
+ | AddressPincode =>
+
+ | BlikCode =>
+ | Currency(currencyArr) =>
+
+ | Country =>
+
+ | AddressCountry(countryArr) =>
+
+ | Bank =>
+
+ | SpecialField(element) => element
+ | InfoElement => <>
+
+ {if fieldsArr->Js.Array2.length > 1 {
+ bottomElement
+ } else {
+
+ }}
+ >
+ | None => React.null
+ }}
+
+ })
+ ->React.array}
+
+}
diff --git a/src/LocaleString.res b/src/LocaleString.res
index c36399c2f..34c133a25 100644
--- a/src/LocaleString.res
+++ b/src/LocaleString.res
@@ -46,6 +46,8 @@ type localeStrings = {
surchargeMsgPercentage: string => string,
surchargeMsgAmountForCard: string => string,
surchargeMsgPercentageForCard: string => string,
+ billingNameLabel: string,
+ billingNamePlaceholder: string,
}
let defaultLocale = {
@@ -101,6 +103,8 @@ let defaultLocale = {
`A surcharge amount of upto ${str} will be applied for this transaction`,
surchargeMsgPercentageForCard: str =>
`A surcharge of upto ${str}% will be applied for this transaction`,
+ billingNameLabel: "Billing name",
+ billingNamePlaceholder: "First and last name",
}
type locale = {localeStrings: array}
@@ -158,6 +162,8 @@ let localeStrings = [
`A surcharge amount of upto ${str} will be applied for this transaction`,
surchargeMsgPercentageForCard: str =>
`A surcharge of upto ${str}% will be applied for this transaction`,
+ billingNameLabel: "Billing name",
+ billingNamePlaceholder: "First and last name",
},
{
locale: "he",
@@ -210,7 +216,10 @@ let localeStrings = [
surchargeMsgPercentage: str => `תוספת של ${str}% תחול עבור עסקה זו`,
surchargeMsgAmountForCard: str =>
`סכום היטל של עד ${str} יחול עבור עסקה זו`,
- surchargeMsgPercentageForCard: str => `תוספת של עד ${str}% תחול על עסקה זו`,
+ surchargeMsgPercentageForCard: str =>
+ `תוספת של עד ${str}% תחול על עסקה זו`,
+ billingNameLabel: `שם החיוב`,
+ billingNamePlaceholder: `שם פרטי ושם משפחה`,
},
{
locale: `fr`,
@@ -261,11 +270,14 @@ let localeStrings = [
card: `Carte`,
surchargeMsgAmount: str =>
`Un montant supplémentaire d'${str} sera appliqué pour cette transaction`,
- surchargeMsgPercentage: str => `Un supplément de ${str}% sera appliqué pour cette transaction`,
+ surchargeMsgPercentage: str =>
+ `Un supplément de ${str}% sera appliqué pour cette transaction`,
surchargeMsgAmountForCard: str =>
`Un montant supplémentaire allant jusqu'à ${str} sera appliqué pour cette transaction.`,
surchargeMsgPercentageForCard: str =>
`Un supplément allant jusqu'à ${str}% sera appliqué pour cette transaction`,
+ billingNameLabel: `Nom de facturation`,
+ billingNamePlaceholder: `Prénom et nom de famille`,
},
{
locale: "en-GB",
@@ -320,6 +332,8 @@ let localeStrings = [
`A surcharge amount of upto ${str} will be applied for this transaction`,
surchargeMsgPercentageForCard: str =>
`A surcharge of upto ${str}% will be applied for this transaction`,
+ billingNameLabel: "Billing name",
+ billingNamePlaceholder: "First and last name",
},
{
locale: "ar",
@@ -376,6 +390,8 @@ let localeStrings = [
`سيتم تطبيق مبلغ إضافي يصل إلى ${str} على هذه المعاملة`,
surchargeMsgPercentageForCard: str =>
`سيتم تطبيق رسوم إضافية تصل إلى ${str}% على هذه المعاملة`,
+ billingNameLabel: `اسم الفواتير`,
+ billingNamePlaceholder: `الاسم الأول والاسم الأخير`,
},
{
locale: "ja",
@@ -425,11 +441,14 @@ let localeStrings = [
enterValidDetailsText: `有効な詳細を入力してください`,
card: `カード`,
surchargeMsgAmount: str => `この取引には ${str} の追加料金が適用されます`,
- surchargeMsgPercentage: str => `この取引には ${str}% の追加料金が適用されます`,
+ surchargeMsgPercentage: str =>
+ `この取引には ${str}% の追加料金が適用されます`,
surchargeMsgAmountForCard: str =>
`この取引には ${str} までの追加料金が適用されます`,
surchargeMsgPercentageForCard: str =>
`この取引には ${str}% までの追加料金が適用されます`,
+ billingNameLabel: `課金名`,
+ billingNamePlaceholder: `名前と苗字`,
},
{
locale: "de",
@@ -485,5 +504,7 @@ let localeStrings = [
`Für diese Transaktion wird ein Zuschlagsbetrag von bis zu ${str} erhoben`,
surchargeMsgPercentageForCard: str =>
`Für diese Transaktion wird ein Zuschlag von bis zu ${str}% erhoben`,
+ billingNameLabel: `Abrechnungsname`,
+ billingNamePlaceholder: `Vor-und Nachname`,
},
]
diff --git a/src/Payments/CardPayment.res b/src/Payments/CardPayment.res
index af3b9650c..0368bf04d 100644
--- a/src/Payments/CardPayment.res
+++ b/src/Payments/CardPayment.res
@@ -77,6 +77,10 @@ let make = (
postFailedSubmitResponse(~errortype="validation_error", ~message)
}
+ let (requiredFieldsBody, setRequiredFieldsBody) = React.useState(_ => Js.Dict.empty())
+
+ let areRequiredFieldsValid = Recoil.useRecoilValueFromAtom(RecoilAtoms.areRequiredFieldsValid)
+
React.useEffect1(() => {
switch customerPaymentMethods {
| LoadingSavedCards => ()
@@ -195,17 +199,30 @@ let make = (
let validFormat =
isCardValid->Belt.Option.getWithDefault(false) &&
isExpiryValid->Belt.Option.getWithDefault(false) &&
- (isBancontact || isCVCValid->Belt.Option.getWithDefault(false))
+ (isBancontact || isCVCValid->Belt.Option.getWithDefault(false)) &&
+ areRequiredFieldsValid
if validFormat && (showFields || isBancontact) {
intent(
- ~bodyArr={isBancontact ? banContactBody : cardBody},
+ ~bodyArr={
+ (isBancontact ? banContactBody : cardBody)
+ ->Js.Dict.fromArray
+ ->Js.Json.object_
+ ->OrcaUtils.flattenObject(true)
+ ->OrcaUtils.mergeTwoFlattenedJsonDicts(requiredFieldsBody)
+ ->OrcaUtils.getArrayOfTupleFromDict
+ },
~confirmParam=confirm.confirmParams,
~handleUserError=false,
(),
)
} else if complete && !empty {
intent(
- ~bodyArr=savedCardBody,
+ ~bodyArr=savedCardBody
+ ->Js.Dict.fromArray
+ ->Js.Json.object_
+ ->OrcaUtils.flattenObject(true)
+ ->OrcaUtils.mergeTwoFlattenedJsonDicts(requiredFieldsBody)
+ ->OrcaUtils.getArrayOfTupleFromDict,
~confirmParam=confirm.confirmParams,
~handleUserError=false,
(),
@@ -311,6 +328,11 @@ let make = (
+ Js.Array.length !== 0}>
+
+
diff --git a/src/Payments/PaymentMethodsRecord.res b/src/Payments/PaymentMethodsRecord.res
index cd554af48..573ada620 100644
--- a/src/Payments/PaymentMethodsRecord.res
+++ b/src/Payments/PaymentMethodsRecord.res
@@ -16,7 +16,7 @@ type paymentMethodsFields =
| AddressCity
| AddressPincode
| AddressState
- | AddressCountry
+ | AddressCountry(array
)
| BlikCode
| Currency(array)
type bankNames = {
@@ -233,7 +233,7 @@ let paymentMethodsFields = [
paymentMethodName: "blik",
icon: Some(icon("blik", ~size=19, ~width=25)),
displayName: "Blik",
- fields: [SpecialField(), InfoElement],
+ fields: [InfoElement],
miniIcon: None,
},
{
@@ -439,29 +439,28 @@ let getPaymentMethodsFieldTypeFromString = str => {
| "user_address_city" => AddressCity
| "user_address_pincode" => AddressPincode
| "user_address_state" => AddressState
- | "user_address_country" => AddressCountry
| "user_blik_code" => BlikCode
+ | "user_billing_name" => BillingName
| _ => None
}
}
let getPaymentMethodsFieldTypeFromDict = dict => {
let keysArr = dict->Js.Dict.keys
- let key =
- keysArr->Js.Array2.find(item => item === "user_currency")->Belt.Option.getWithDefault("")
+ let key = keysArr->Belt.Array.get(0)->Belt.Option.getWithDefault("")
switch key {
| "user_currency" => {
- let options =
- dict
- ->Js.Dict.get("user_currency")
- ->Belt.Option.flatMap(Js.Json.decodeObject)
- ->Belt.Option.getWithDefault(Js.Dict.empty())
- ->Js.Dict.get("options")
- ->Belt.Option.flatMap(Js.Json.decodeArray)
- ->Belt.Option.getWithDefault([])
- ->Belt.Array.keepMap(Js.Json.decodeString)
+ let options = dict->Utils.getArrayValFromJsonDict("user_currency", "options")
Currency(options)
}
+ | "user_address_country" => {
+ let options = dict->Utils.getArrayValFromJsonDict("user_address_country", "options")
+ switch options->Belt.Array.get(0)->Belt.Option.getWithDefault("") {
+ | "" => None
+ | "ALL" => AddressCountry(Country.country->Js.Array2.map(item => item.countryName))
+ | _ => AddressCountry(options)
+ }
+ }
| _ => None
}
}
@@ -494,9 +493,11 @@ let getRequiredFieldsFromJson = dict => {
}
}
+let dynamicFieldsEnabledPaymentMethods = ["crypto_currency", "debit", "credit", "blik"]
+
let getPaymentMethodFields = (paymentMethod, requiredFields) => {
let requiredFieldsArr =
- paymentMethod === "crypto_currency"
+ dynamicFieldsEnabledPaymentMethods->Js.Array2.includes(paymentMethod)
? requiredFields
->Utils.getDictFromJson
->Js.Dict.values
diff --git a/src/Payments/PaymentMethodsWrapper.res b/src/Payments/PaymentMethodsWrapper.res
index 45ef689ec..0bb04d97e 100644
--- a/src/Payments/PaymentMethodsWrapper.res
+++ b/src/Payments/PaymentMethodsWrapper.res
@@ -9,11 +9,11 @@ type props = {
}
let default = (props: props) => {
- let {publishableKey, iframeId} = Recoil.useRecoilValueFromAtom(keys)
+ let {iframeId} = Recoil.useRecoilValueFromAtom(keys)
let loggerState = Recoil.useRecoilValueFromAtom(loggerAtom)
let blikCode = Recoil.useRecoilValueFromAtom(userBlikCode)
let phoneNumber = Recoil.useRecoilValueFromAtom(userPhoneNumber)
- let {config, themeObj, localeString} = Recoil.useRecoilValueFromAtom(configAtom)
+ let {themeObj} = Recoil.useRecoilValueFromAtom(configAtom)
let intent = PaymentHelpers.usePaymentIntent(Some(loggerState), Other)
let optionPaymentMethodDetails =
props.list
@@ -32,84 +32,25 @@ let default = (props: props) => {
->Belt.Option.getWithDefault(RedirectToURL)
let (fullName, _) = Recoil.useLoggedRecoilState(userFullName, "fullName", loggerState)
let (email, _) = Recoil.useLoggedRecoilState(userEmailAddress, "email", loggerState)
- let (currency, setCurrency) = Recoil.useLoggedRecoilState(userCurrency, "currency", loggerState)
- let (country, setCountry) = Recoil.useRecoilState(userCountry)
- let (selectedBank, setSelectedBank) = Recoil.useRecoilState(userBank)
- let {fields} = Recoil.useRecoilValueFromAtom(optionAtom)
+ let (currency, _) = Recoil.useLoggedRecoilState(userCurrency, "currency", loggerState)
+ let (country, _) = Recoil.useRecoilState(userCountry)
+ let (selectedBank, _) = Recoil.useRecoilState(userBank)
let setFieldComplete = Recoil.useSetRecoilState(fieldsComplete)
- let showDetails = PaymentType.getShowAddressDetails(
- ~billingDetails=fields.billingDetails,
- ~logger=loggerState,
- )
- let countryNames = Utils.getCountryNames(Country.getCountry(props.paymentMethodName))
- let bankNames =
- Bank.getBanks(props.paymentMethodName)->Utils.getBankNames(paymentMethodDetails.bankNames)
- let setCountry = val => {
- setCountry(. val)
- }
- let setCurrency = val => {
- setCurrency(. val)
- }
- let setSelectedBank = val => {
- setSelectedBank(. val)
- }
let cleanBlik = str => str->Js.String2.replaceByRe(%re("/-/g"), "")
let cleanPhoneNumber = str => str->Js.String2.replaceByRe(%re("/\s/g"), "")
- React.useEffect0(() => {
- let clientTimeZone = dateTimeFormat(.).resolvedOptions(.).timeZone
- let clientCountry = getClientCountry(clientTimeZone)
- setCountry(_ => clientCountry.countryName)
- let bank = bankNames->Belt.Array.get(0)->Belt.Option.getWithDefault("")
- setSelectedBank(_ => bank)
- None
- })
- //<...>//
- let requiredField =
- PaymentMethodsRecord.getPaymentMethodTypeFromList(
- ~list=props.list,
- ~paymentMethod=paymentMethodDetails.methodType,
- ~paymentMethodType=paymentMethodDetails.paymentMethodName,
- )->Belt.Option.getWithDefault(PaymentMethodsRecord.defaultPaymentMethodType)
- let fieldsArr =
- props.paymentMethodName->PaymentMethodsRecord.getPaymentMethodFields(
- requiredField.required_fields,
- )
- //<...>//
- let complete = React.useMemo4(() => {
- fieldsArr
- ->Js.Array2.map(field => {
- switch field {
- | Email => email.value != "" && email.isValid->Belt.Option.getWithDefault(false)
- | FullName => fullName.value !== ""
- | Country => country !== ""
- | _ => true
- }
- })
- ->Js.Array2.reduce((acc, condition) => {
- acc && condition
- }, true)
- }, (props.paymentMethodName, email, fullName, country))
+
+ let (requiredFieldsBody, setRequiredFieldsBody) = React.useState(_ => Js.Dict.empty())
+ let areRequiredFieldsValid = Recoil.useRecoilValueFromAtom(RecoilAtoms.areRequiredFieldsValid)
+ let areRequiredFieldsEmpty = Recoil.useRecoilValueFromAtom(RecoilAtoms.areRequiredFieldsEmpty)
+
+ let complete = areRequiredFieldsValid
React.useEffect1(() => {
setFieldComplete(._ => complete)
None
}, [complete])
- let empty = React.useMemo4(() => {
- props.paymentMethodName
- ->PaymentMethodsRecord.getPaymentMethodFields(requiredField.required_fields)
- ->Js.Array2.map(field => {
- switch field {
- | Email => email.value == ""
- | FullName => fullName.value == ""
- | Country => country == ""
- | _ => false
- }
- })
- ->Js.Array2.reduce((acc, condition) => {
- acc || condition
- }, false)
- }, (props.paymentMethodName, email, fullName, country))
+ let empty = areRequiredFieldsEmpty
React.useEffect2(() => {
handlePostMessageEvents(
@@ -148,7 +89,12 @@ let default = (props: props) => {
~phoneNumber=phoneNumber.value->cleanPhoneNumber,
~paymentExperience=paymentFlow,
~currency,
- ),
+ )
+ ->Js.Dict.fromArray
+ ->Js.Json.object_
+ ->OrcaUtils.flattenObject(true)
+ ->OrcaUtils.mergeTwoFlattenedJsonDicts(requiredFieldsBody)
+ ->OrcaUtils.getArrayOfTupleFromDict,
~confirmParam=confirm.confirmParams,
~handleUserError=false,
~iframeId,
@@ -165,63 +111,20 @@ let default = (props: props) => {
blikCode,
props.paymentMethodName,
phoneNumber.value,
- (selectedBank, currency),
+ (selectedBank, currency, requiredFieldsBody),
))
submitPaymentData(submitCallback)
- let bottomElement =
- {fieldsArr
- ->Js.Array2.map(field => {
- switch field {
- | Email =>
- | FullName =>
- | Country =>
-
-
-
- | Bank =>
-
- | SpecialField(element) => element
- | InfoElement => <>
-
- {if fieldsArr->Js.Array2.length > 1 {
-
- } else {
-
- }}
- >
- | Currency(currencyArr) =>
-
- | _ => React.null
- }
- })
- ->React.array}
+ Js.Array.length !== 0}>
+
+
}
diff --git a/src/Utilities/RecoilAtoms.res b/src/Utilities/RecoilAtoms.res
index f112f325b..02166074f 100644
--- a/src/Utilities/RecoilAtoms.res
+++ b/src/Utilities/RecoilAtoms.res
@@ -49,3 +49,6 @@ let fieldsComplete = Recoil.atom(. "fieldsComplete", false)
let isManualRetryEnabled = Recoil.atom(. "isManualRetryEnabled", false)
let userCurrency = Recoil.atom(. "userCurrency", "")
let isShowOrPayUsing = Recoil.atom(. "isShowOrPayUsing", false)
+let areRequiredFieldsValid = Recoil.atom(. "areRequiredFieldsValid", false)
+let areRequiredFieldsEmpty = Recoil.atom(. "areRequiredFieldsEmpty", true)
+let userBillingName = Recoil.atom(. "userBillingName", defaultFieldValues)
diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res
index 8271a52bc..cb7e57d1a 100644
--- a/src/Utilities/Utils.res
+++ b/src/Utilities/Utils.res
@@ -347,7 +347,7 @@ let getClientCountry = clientTimeZone => {
->Belt.Option.getWithDefault(Country.defaultTimeZone)
}
-let removeDuplicate = (arr: array) => {
+let removeDuplicate = arr => {
arr->Js.Array2.filteri((item, i) => {
arr->Js.Array2.indexOf(item) === i
})
diff --git a/src/orca-loader/OrcaUtils.res b/src/orca-loader/OrcaUtils.res
index 0623fd87b..aac452edf 100644
--- a/src/orca-loader/OrcaUtils.res
+++ b/src/orca-loader/OrcaUtils.res
@@ -315,3 +315,18 @@ let getThemePromise = dict => {
| _ => None
}
}
+
+let mergeTwoFlattenedJsonDicts = (dict1, dict2) => {
+ dict1
+ ->Js.Dict.entries
+ ->Js.Array2.concat(dict2->Js.Dict.entries)
+ ->Js.Dict.fromArray
+ ->Js.Json.object_
+ ->unflattenObject
+}
+
+let getArrayOfTupleFromDict = dict => {
+ dict
+ ->Js.Dict.keys
+ ->Belt.Array.map(key => (key, Js.Dict.get(dict, key)->Belt.Option.getWithDefault(Js.Json.null)))
+}