diff --git a/src/Components/DynamicFields.res b/src/Components/DynamicFields.res
index 52135e3ab..f1344d92b 100644
--- a/src/Components/DynamicFields.res
+++ b/src/Components/DynamicFields.res
@@ -42,7 +42,6 @@ let make = (
paymentMethodTypes.required_fields
->Array.concat(creditRequiredFields)
->DynamicFieldsUtils.removeRequiredFieldsDuplicates
- ->DynamicFieldsUtils.filterCardDetailsIfSavedCardsFlow(isSavedCardFlow)
} else if (
PaymentMethodsRecord.dynamicFieldsEnabledPaymentMethods->Array.includes(paymentMethodType)
) {
@@ -50,7 +49,7 @@ let make = (
} else {
[]
}
- }, (paymentMethod, paymentMethodTypes.required_fields, paymentMethodType, isSavedCardFlow))
+ }, (paymentMethod, paymentMethodTypes.required_fields, paymentMethodType))
let requiredFields = React.useMemo(() => {
requiredFieldsWithBillingDetails->DynamicFieldsUtils.removeBillingDetailsIfUseBillingAddress(
@@ -71,13 +70,7 @@ let make = (
~isAllStoredCardsHaveName,
(),
)
- ->DynamicFieldsUtils.updateDynamicFields(
- billingAddress,
- ~paymentMethodListValue,
- ~paymentMethod,
- ~isSavedCardFlow,
- (),
- )
+ ->DynamicFieldsUtils.updateDynamicFields(billingAddress, ())
->Belt.SortArray.stableSortBy(PaymentMethodsRecord.sortPaymentMethodFields)
//<...>//
}, (requiredFields, isAllStoredCardsHaveName, isSavedCardFlow))
@@ -167,7 +160,7 @@ let make = (
cardRef,
icon,
cardError,
- setCardError,
+ _,
maxCardLength,
) = switch cardProps {
| Some(cardProps) => cardProps
@@ -183,7 +176,7 @@ let make = (
expiryRef,
_,
expiryError,
- setExpiryError,
+ _,
) = switch expiryProps {
| Some(expiryProps) => expiryProps
| None => defaultExpiryProps
@@ -199,7 +192,7 @@ let make = (
cvcRef,
_,
cvcError,
- setCvcError,
+ _,
) = switch cvcProps {
| Some(cvcProps) => cvcProps
| None => defaultCvcProps
@@ -294,17 +287,9 @@ let make = (
~isSavedCardFlow,
~isAllStoredCardsHaveName,
~setRequiredFieldsBody,
- ~paymentMethodListValue,
)
- let submitCallback = DynamicFieldsUtils.useSubmitCallback(
- ~cardNumber,
- ~setCardError,
- ~cardExpiry,
- ~setExpiryError,
- ~cvcNumber,
- ~setCvcError,
- )
+ let submitCallback = DynamicFieldsUtils.useSubmitCallback()
useSubmitPaymentData(submitCallback)
let bottomElement =
@@ -352,7 +337,7 @@ let make = (
key={`outside-billing-${index->Int.toString}`}
className="flex flex-col w-full place-content-between"
style={ReactDOMStyle.make(
- ~marginTop=index !== 0 ? themeObj.spacingGridColumn : "",
+ ~marginTop=index !== 0 || paymentMethod === "card" ? themeObj.spacingGridColumn : "",
~gridColumnGap=themeObj.spacingGridRow,
(),
)}>
diff --git a/src/Payment.res b/src/Payment.res
index 94b14daee..8d15eec44 100644
--- a/src/Payment.res
+++ b/src/Payment.res
@@ -228,6 +228,13 @@ let make = (~paymentMode, ~integrateError, ~logger) => {
checkCardExpiry(getCardElementValue(iframeId, "card-expiry"))
| _ => true
}
+ let cardNetwork = {
+ if cardBrand != "" {
+ [("card_network", cardNumber->CardUtils.getCardBrand->JSON.Encode.string)]
+ } else {
+ []
+ }
+ }
if validFormat {
let body = switch paymentMode->getPaymentMode {
| Card =>
@@ -239,7 +246,7 @@ let make = (~paymentMode, ~integrateError, ~logger) => {
~year,
~cardHolderName="",
~cvcNumber,
- ~cardBrand,
+ ~cardBrand=cardNetwork,
(),
)
| CardNumberElement =>
@@ -251,7 +258,7 @@ let make = (~paymentMode, ~integrateError, ~logger) => {
~year,
~cardHolderName="",
~cvcNumber=localCvcNumber,
- ~cardBrand,
+ ~cardBrand=cardNetwork,
(),
)
| _ => []
diff --git a/src/Payments/CardPayment.res b/src/Payments/CardPayment.res
index 01d79228e..85725a1ee 100644
--- a/src/Payments/CardPayment.res
+++ b/src/Payments/CardPayment.res
@@ -14,22 +14,59 @@ let make = (
open Utils
open UtilityHooks
- let {themeObj, localeString} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom)
+ let {config, themeObj, localeString} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom)
+ let {innerLayout} = config.appearance
let options = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom)
let loggerState = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom)
let paymentMethodListValue = Recoil.useRecoilValueFromAtom(PaymentUtils.paymentMethodListValue)
let (nickname, setNickname) = React.useState(_ => "")
- let (_, _, cardNumber, _, _, _, _, _, _, _) = cardProps
+ let (
+ isCardValid,
+ setIsCardValid,
+ cardNumber,
+ changeCardNumber,
+ handleCardBlur,
+ cardRef,
+ icon,
+ cardError,
+ setCardError,
+ maxCardLength,
+ ) = cardProps
let cardBrand = React.useMemo(() => {
cardNumber->CardUtils.getCardBrand
}, [cardNumber])
+ let (
+ isExpiryValid,
+ setIsExpiryValid,
+ cardExpiry,
+ changeCardExpiry,
+ handleExpiryBlur,
+ expiryRef,
+ _,
+ expiryError,
+ setExpiryError,
+ ) = expiryProps
+
+ let (
+ isCVCValid,
+ setIsCVCValid,
+ cvcNumber,
+ _,
+ changeCVCNumber,
+ handleCVCBlur,
+ cvcRef,
+ _,
+ cvcError,
+ setCvcError,
+ ) = cvcProps
let {displaySavedPaymentMethodsCheckbox} = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom)
let intent = PaymentHelpers.usePaymentIntent(Some(loggerState), Card)
let showFields = Recoil.useRecoilValueFromAtom(RecoilAtoms.showCardFieldsAtom)
+ let setComplete = Recoil.useSetRecoilState(RecoilAtoms.fieldsComplete)
let (isSaveCardsChecked, setIsSaveCardsChecked) = React.useState(_ => false)
let setUserError = message => {
@@ -39,15 +76,23 @@ let make = (
let (requiredFieldsBody, setRequiredFieldsBody) = React.useState(_ => Dict.make())
let areRequiredFieldsValid = Recoil.useRecoilValueFromAtom(RecoilAtoms.areRequiredFieldsValid)
- let areRequiredFieldsEmpty = Recoil.useRecoilValueFromAtom(RecoilAtoms.areRequiredFieldsEmpty)
- useHandlePostMessages(
- ~complete=areRequiredFieldsValid,
- ~empty=areRequiredFieldsEmpty,
- ~paymentType="card",
- )
+ let complete = isAllValid(isCardValid, isCVCValid, isExpiryValid, true, "payment")
+ let empty = cardNumber == "" || cardExpiry == "" || cvcNumber == ""
+ React.useEffect(() => {
+ setComplete(_ => complete)
+ None
+ }, [complete])
+
+ useHandlePostMessages(~complete=complete && areRequiredFieldsValid, ~empty, ~paymentType="card")
let isGuestCustomer = useIsGuestCustomer()
+ let isCvcValidValue = CardUtils.getBoolOptionVal(isCVCValid)
+ let (cardEmpty, cardComplete, cardInvalid) = CardUtils.useCardDetails(
+ ~cvcNumber,
+ ~isCVCValid,
+ ~isCvcValidValue,
+ )
let isCustomerAcceptanceRequired = useIsCustomerAcceptanceRequired(
~displaySavedPaymentMethodsCheckbox,
@@ -58,9 +103,26 @@ let make = (
let submitCallback = React.useCallback((ev: Window.event) => {
let json = ev.data->JSON.parseExn
let confirm = json->getDictFromJson->ConfirmType.itemToObjMapper
+ let (month, year) = CardUtils.getExpiryDates(cardExpiry)
let onSessionBody = [("customer_acceptance", PaymentBody.customerAcceptanceBody)]
- let defaultCardBody = PaymentBody.dynamicCardPaymentBody(~cardBrand, ~nickname, ())
+ let cardNetwork = {
+ if cardBrand != "" {
+ [("card_network", cardBrand->JSON.Encode.string)]
+ } else {
+ []
+ }
+ }
+ let defaultCardBody = PaymentBody.cardPaymentBody(
+ ~cardNumber,
+ ~month,
+ ~year,
+ ~cardHolderName="",
+ ~cvcNumber,
+ ~cardBrand=cardNetwork,
+ ~nickname,
+ (),
+ )
let banContactBody = PaymentBody.bancontactBody()
let cardBody = if isCustomerAcceptanceRequired {
defaultCardBody->Array.concat(onSessionBody)
@@ -68,7 +130,11 @@ let make = (
defaultCardBody
}
if confirm.doSubmit {
- let validFormat = areRequiredFieldsValid
+ let validFormat =
+ (isBancontact ||
+ (isCVCValid->Option.getOr(false) &&
+ isCardValid->Option.getOr(false) &&
+ isExpiryValid->Option.getOr(false))) && areRequiredFieldsValid
if validFormat && (showFields || isBancontact) {
intent(
~bodyArr={
@@ -83,11 +149,32 @@ let make = (
~handleUserError=false,
(),
)
- } else if !validFormat {
- setUserError(localeString.enterValidDetailsText)
+ } else {
+ if cardNumber === "" {
+ setCardError(_ => localeString.cardNumberEmptyText)
+ setUserError(localeString.enterFieldsText)
+ }
+ if cardExpiry === "" {
+ setExpiryError(_ => localeString.cardExpiryDateEmptyText)
+ setUserError(localeString.enterFieldsText)
+ }
+ if !isBancontact && cvcNumber === "" {
+ setCvcError(_ => localeString.cvcNumberEmptyText)
+ setUserError(localeString.enterFieldsText)
+ }
+ if !validFormat {
+ setUserError(localeString.enterValidDetailsText)
+ }
}
}
- }, (areRequiredFieldsValid, requiredFieldsBody, isCustomerAcceptanceRequired, nickname))
+ }, (
+ areRequiredFieldsValid,
+ requiredFieldsBody,
+ empty,
+ complete,
+ isCustomerAcceptanceRequired,
+ nickname,
+ ))
useSubmitPaymentData(submitCallback)
let paymentMethod = isBancontact ? "bank_redirect" : "card"
@@ -101,12 +188,114 @@ let make = (
let nicknameFieldClassName = conditionsForShowingSaveCardCheckbox ? "pt-2" : "pt-5"
+ let compressedLayoutStyleForCvcError =
+ innerLayout === Compressed && cvcError->String.length > 0 ? "!border-l-0" : ""
+
+
+
+ {React.string(localeString.cardHeader)}
+
+
+
+ String.length > 0
+ ? "border-b-0"
+ : ""}
+ />
+
+ String.length > 0 ||
+ cvcError->String.length > 0 ||
+ expiryError->String.length > 0}>
+
+ {React.string("Invalid input")}
+
+
+
{
- switch str {
- | "user_email_address" => Email
- | "user_full_name" => FullName
- | "user_country" => Country
- | "user_bank" => Bank
- | "user_phone_number" => PhoneNumber
- | "user_address_line1" => AddressLine1
- | "user_address_line2" => AddressLine2
- | "user_address_city" => AddressCity
- | "user_address_pincode" => AddressPincode
- | "user_address_state" => AddressState
- | "user_blik_code" => BlikCode
- | "user_billing_name" => BillingName
- | "user_card_number" => CardNumber
- | "user_card_expiry_month" => CardExpiryMonth
- | "user_card_expiry_year" => CardExpiryYear
- | "user_card_cvc" => CardCvc
+let getPaymentMethodsFieldTypeFromString = (str, isBancontact) => {
+ switch (str, isBancontact) {
+ | ("user_email_address", _) => Email
+ | ("user_full_name", _) => FullName
+ | ("user_country", _) => Country
+ | ("user_bank", _) => Bank
+ | ("user_phone_number", _) => PhoneNumber
+ | ("user_address_line1", _) => AddressLine1
+ | ("user_address_line2", _) => AddressLine2
+ | ("user_address_city", _) => AddressCity
+ | ("user_address_pincode", _) => AddressPincode
+ | ("user_address_state", _) => AddressState
+ | ("user_blik_code", _) => BlikCode
+ | ("user_billing_name", _) => BillingName
+ | ("user_card_number", true) => CardNumber
+ | ("user_card_expiry_month", true) => CardExpiryMonth
+ | ("user_card_expiry_year", true) => CardExpiryYear
+ | ("user_card_cvc", true) => CardCvc
| _ => None
}
}
@@ -558,7 +558,7 @@ let getPaymentMethodsFieldTypeFromDict = dict => {
}
}
-let getFieldType = dict => {
+let getFieldType = (dict, isBancontact) => {
let fieldClass =
dict
->Dict.get("field_type")
@@ -570,7 +570,7 @@ let getFieldType = dict => {
None
| Number(_val) => None
| Array(_arr) => None
- | String(val) => val->getPaymentMethodsFieldTypeFromString
+ | String(val) => val->getPaymentMethodsFieldTypeFromString(isBancontact)
| Object(dict) => dict->getPaymentMethodsFieldTypeFromDict
}
}
@@ -614,16 +614,6 @@ let getIsAnyBillingDetailEmpty = (requiredFields: array) => {
})
}
-let filterCardDetailsFromSavedPaymentMethod = fieldType => {
- switch fieldType {
- | CardNumber
- | CardExpiryMonth
- | CardExpiryYear
- | CardCvc => true
- | _ => false
- }
-}
-
let getPaymentMethodFields = (
paymentMethod,
requiredFields: array,
@@ -872,7 +862,7 @@ let getAchConnectors = (dict, str) => {
->getStrArray("elligible_connectors")
}
-let getDynamicFieldsFromJsonDict = dict => {
+let getDynamicFieldsFromJsonDict = (dict, isBancontact) => {
let requiredFields =
Utils.getJsonFromDict(dict, "required_fields", JSON.Encode.null)
->Utils.getDictFromJson
@@ -883,7 +873,7 @@ let getDynamicFieldsFromJsonDict = dict => {
{
required_field: requiredFieldsDict->Utils.getString("required_field", ""),
display_name: requiredFieldsDict->Utils.getString("display_name", ""),
- field_type: requiredFieldsDict->getFieldType,
+ field_type: requiredFieldsDict->getFieldType(isBancontact),
value: requiredFieldsDict->Utils.getString("value", ""),
}
})
@@ -904,7 +894,9 @@ let getPaymentMethodTypes = (dict, str) => {
bank_names: getBankNames(jsonDict, "bank_names"),
bank_debits_connectors: getAchConnectors(jsonDict, "bank_debit"),
bank_transfers_connectors: getAchConnectors(jsonDict, "bank_transfer"),
- required_fields: jsonDict->getDynamicFieldsFromJsonDict,
+ required_fields: jsonDict->getDynamicFieldsFromJsonDict(
+ paymentMethodType === "bancontact_card",
+ ),
surcharge_details: jsonDict->getSurchargeDetails,
}
})
@@ -1067,5 +1059,3 @@ let paymentMethodFieldToStrMapper = (field: paymentMethodsFields) => {
| CardExpiryAndCvc => "CardExpiryAndCvc"
}
}
-
-let cardDetailsFields = [CardNumber, CardExpiryMonth, CardExpiryYear, CardCvc]
diff --git a/src/Utilities/DynamicFieldsUtils.res b/src/Utilities/DynamicFieldsUtils.res
index dc0e77bb5..56421f1d9 100644
--- a/src/Utilities/DynamicFieldsUtils.res
+++ b/src/Utilities/DynamicFieldsUtils.res
@@ -52,16 +52,6 @@ let getBillingAddressPathFromFieldType = (fieldType: PaymentMethodsRecord.paymen
}
}
-let getCardAddressPathFromFieldType = (fieldType: PaymentMethodsRecord.paymentMethodsFields) => {
- switch fieldType {
- | CardNumber => "payment_method_data.card.card_number"
- | CardExpiryMonth => "payment_method_data.card.card_exp_month"
- | CardExpiryYear => "payment_method_data.card.card_exp_year"
- | CardCvc => "payment_method_data.card.card_cvc"
- | _ => ""
- }
-}
-
let removeBillingDetailsIfUseBillingAddress = (
requiredFields: array,
billingAddress: PaymentType.billingAddress,
@@ -154,6 +144,7 @@ let useRequiredFieldsEmptyAndValid = (
| StateAndCity => state.value !== "" && city.value !== ""
| CountryAndPincode(countryArr) =>
(country !== "" || countryArr->Array.length === 0) && postalCode.value !== ""
+
| AddressCity => city.value !== ""
| AddressPincode => postalCode.value !== ""
| AddressState => state.value !== ""
@@ -386,7 +377,6 @@ let useRequiredFieldsBody = (
~isSavedCardFlow,
~isAllStoredCardsHaveName,
~setRequiredFieldsBody,
- ~paymentMethodListValue: PaymentMethodsRecord.paymentMethodList,
) => {
let email = Recoil.useRecoilValueFromAtom(userEmailAddress)
let fullName = Recoil.useRecoilValueFromAtom(userFullName)
@@ -474,23 +464,6 @@ let useRequiredFieldsBody = (
}
}
- let addCardDetailsBodyIfFallback = requiredFieldsBody => {
- if (
- (paymentMethodType === "debit" || paymentMethodType === "credit") &&
- paymentMethodListValue.payment_methods->Array.length === 0 &&
- !isSavedCardFlow
- ) {
- PaymentMethodsRecord.cardDetailsFields->Array.reduce(requiredFieldsBody, (acc, item) => {
- let value = item->getFieldValueFromFieldType
- let path = item->getCardAddressPathFromFieldType
- acc->Dict.set(path, value->JSON.Encode.string)
- acc
- })
- } else {
- requiredFieldsBody
- }
- }
-
React.useEffect(() => {
let requiredFieldsBody =
requiredFields
@@ -519,7 +492,6 @@ let useRequiredFieldsBody = (
acc
})
->addBillingDetailsIfUseBillingAddress
- ->addCardDetailsBodyIfFallback
setRequiredFieldsBody(_ => requiredFieldsBody)
None
@@ -646,54 +618,26 @@ let combineCardExpiryAndCvc = arr => {
}
}
-let addCardDetailsIfFallback = (
- fieldsArr,
- ~paymentMethodListValue: PaymentMethodsRecord.paymentMethodList,
- ~paymentMethod,
- ~isSavedCardFlow,
-) => {
- if (
- paymentMethod === "card" &&
- paymentMethodListValue.payment_methods->Array.length === 0 &&
- !isSavedCardFlow
- ) {
- fieldsArr->Array.concat(PaymentMethodsRecord.cardDetailsFields)
- } else {
- fieldsArr
- }
-}
-
let updateDynamicFields = (
arr: array,
billingAddress,
- ~paymentMethodListValue: PaymentMethodsRecord.paymentMethodList,
- ~paymentMethod,
- ~isSavedCardFlow,
(),
) => {
arr
->Utils.removeDuplicate
->Array.filter(item => item !== None)
->addBillingAddressIfUseBillingAddress(billingAddress)
- ->addCardDetailsIfFallback(~paymentMethodListValue, ~paymentMethod, ~isSavedCardFlow)
->combineStateAndCity
->combineCountryAndPostal
->combineCardExpiryMonthAndYear
->combineCardExpiryAndCvc
}
-let useSubmitCallback = (
- ~cardNumber,
- ~setCardError,
- ~cardExpiry,
- ~setExpiryError,
- ~cvcNumber,
- ~setCvcError,
-) => {
- let logger = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom)
- let (line1, setLine1) = Recoil.useLoggedRecoilState(RecoilAtoms.userAddressline1, "line1", logger)
- let (line2, setLine2) = Recoil.useLoggedRecoilState(RecoilAtoms.userAddressline2, "line2", logger)
- let (state, setState) = Recoil.useLoggedRecoilState(RecoilAtoms.userAddressState, "state", logger)
+let useSubmitCallback = () => {
+ let logger = Recoil.useRecoilValueFromAtom(loggerAtom)
+ let (line1, setLine1) = Recoil.useLoggedRecoilState(userAddressline1, "line1", logger)
+ let (line2, setLine2) = Recoil.useLoggedRecoilState(userAddressline2, "line2", logger)
+ let (state, setState) = Recoil.useLoggedRecoilState(userAddressState, "state", logger)
let (postalCode, setPostalCode) = Recoil.useLoggedRecoilState(
userAddressPincode,
"postal_code",
@@ -738,17 +682,8 @@ let useSubmitCallback = (
errorString: localeString.cityEmptyText,
})
}
- if cardNumber === "" {
- setCardError(_ => localeString.cardNumberEmptyText)
- }
- if cardExpiry === "" {
- setExpiryError(_ => localeString.cardExpiryDateEmptyText)
- }
- if cvcNumber === "" {
- setCvcError(_ => localeString.cvcNumberEmptyText)
- }
}
- }, (line1, line2, state, city, postalCode, cardNumber, cardExpiry, cvcNumber))
+ }, (line1, line2, state, city, postalCode))
}
let usePaymentMethodTypeFromList = (
@@ -803,16 +738,3 @@ let removeRequiredFieldsDuplicates = (
requiredFields
}
-
-let filterCardDetailsIfSavedCardsFlow = (
- requiredFields: array,
- isSavedCardFlow,
-) => {
- if isSavedCardFlow {
- requiredFields->Array.filter(requiredField => {
- requiredField.field_type->PaymentMethodsRecord.filterCardDetailsFromSavedPaymentMethod->not
- })
- } else {
- requiredFields
- }
-}
diff --git a/src/Utilities/PaymentBody.res b/src/Utilities/PaymentBody.res
index e6f75bcea..d3b7ab42d 100644
--- a/src/Utilities/PaymentBody.res
+++ b/src/Utilities/PaymentBody.res
@@ -58,48 +58,17 @@ let cardPaymentBody = (
cardBody->Array.push(("nick_name", nickname->JSON.Encode.string))->ignore
}
- if cardBrand != "" {
- cardBody->Array.push(("card_network", cardBrand->JSON.Encode.string))->ignore
- }
-
[
("payment_method", "card"->JSON.Encode.string),
(
"payment_method_data",
- [("card", cardBody->Dict.fromArray->JSON.Encode.object)]
+ [("card", cardBody->Array.concat(cardBrand)->Dict.fromArray->JSON.Encode.object)]
->Dict.fromArray
->JSON.Encode.object,
),
]
}
-let dynamicCardPaymentBody = (~cardBrand, ~nickname="", ()) => {
- let cardBody = []
-
- if nickname != "" {
- cardBody->Array.push(("nick_name", nickname->JSON.Encode.string))->ignore
- }
-
- if cardBrand != "" {
- cardBody->Array.push(("card_network", cardBrand->JSON.Encode.string))->ignore
- }
-
- let paymentMethodData = if cardBody->Array.length > 0 {
- [
- (
- "payment_method_data",
- [("card", cardBody->Dict.fromArray->JSON.Encode.object)]
- ->Dict.fromArray
- ->JSON.Encode.object,
- ),
- ]
- } else {
- []
- }
-
- [("payment_method", "card"->JSON.Encode.string)]->Array.concat(paymentMethodData)
-}
-
let bancontactBody = () => [
("payment_method", "bank_redirect"->JSON.Encode.string),
("payment_method_type", "bancontact_card"->JSON.Encode.string),