Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cvc nickname gpay #224

Merged
merged 6 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/Components/DynamicFields.res
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,11 @@ let make = (
let {billingAddress} = Recoil.useRecoilValueFromAtom(optionAtom)

//<...>//
let paymentMethodTypes = React.useMemo3(() => {
PaymentMethodsRecord.getPaymentMethodTypeFromList(
~list,
~paymentMethod,
~paymentMethodType=PaymentUtils.getPaymentMethodName(
~paymentMethodType=paymentMethod,
~paymentMethodName=paymentMethodType,
),
)->Belt.Option.getWithDefault(PaymentMethodsRecord.defaultPaymentMethodType)
}, (list, paymentMethod, paymentMethodType))
let paymentMethodTypes = DynamicFieldsUtils.usePaymentMethodTypeFromList(
~list,
~paymentMethod,
~paymentMethodType,
)

let requiredFieldsWithBillingDetails = React.useMemo3(() => {
if paymentMethod === "card" {
Expand Down
19 changes: 19 additions & 0 deletions src/Components/NicknamePaymentInput.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@react.component
let make = (~paymentType: CardThemeType.mode, ~value, ~setValue) => {
let {config, localeString} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom)

let onChange = ev => {
let val = ReactEvent.Form.target(ev)["value"]
setValue(_ => val)
}

<PaymentInputField
fieldName=localeString.nicknameLabel
value
onChange
paymentType
appearance=config.appearance
inputRef={React.useRef(Js.Nullable.null)}
placeholder=localeString.nicknamePlaceholder
/>
}
19 changes: 10 additions & 9 deletions src/Components/SavedCardItem.res
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ let make = (
}, [isActive])

let isCard = paymentItem.paymentMethod === "card"
let isRenderCvv = isCard && paymentItem.requiresCvv

let paymentMethodType = switch paymentItem.paymentMethodType {
| Some(paymentMethodType) => paymentMethodType->Utils.snakeToTitleCase
Expand Down Expand Up @@ -90,15 +91,15 @@ let make = (
border="1px solid currentColor"
/>
</div>
<div className={`PickerItemIcon mx-3 flex items-center `}>
brandIcon
</div>
<div className="flex items-center gap-2">
<div className={`PickerItemIcon mx-3 flex items-center `}> brandIcon </div>
<div className="flex items-center gap-4">
{isCard
? <div
className={`PickerItemLabel flex flex-row gap-3 items-center`}>
<div className="tracking-widest"> {React.string(`****`)} </div>
<div> {React.string({paymentItem.card.last4Digits})} </div>
? <div className="flex flex-col items-start">
<div> {React.string(paymentItem.card.nickname)} </div>
<div className={`PickerItemLabel flex flex-row gap-3 items-center`}>
<div className="tracking-widest"> {React.string(`****`)} </div>
<div> {React.string(paymentItem.card.last4Digits)} </div>
</div>
</div>
: <div> {React.string(paymentMethodType)} </div>}
<RenderIf condition={paymentItem.defaultPaymentMethodSet}>
Expand All @@ -125,7 +126,7 @@ let make = (
<div className="w-full ">
<RenderIf condition={isActive}>
<div className="flex flex-col items-start mx-8">
<RenderIf condition={isCard}>
<RenderIf condition={isRenderCvv}>
<div
className={`flex flex-row items-start justify-start gap-2`}
style={ReactDOMStyle.make(~fontSize="14px", ~opacity="0.5", ())}>
Expand Down
13 changes: 11 additions & 2 deletions src/Components/SavedMethods.res
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,16 @@ let make = (
->Belt.Array.get(0)
->Belt.Option.getWithDefault(PaymentType.defaultCustomerMethods)
let isCardPaymentMethod = customerMethod.paymentMethod === "card"
let isCardPaymentMethodValid = !customerMethod.requiresCvv || (complete && !empty)

let savedPaymentMethodBody = switch customerMethod.paymentMethod {
| "card" => PaymentBody.savedCardBody(~paymentToken=token, ~customerId, ~cvcNumber)
| "card" =>
PaymentBody.savedCardBody(
~paymentToken=token,
~customerId,
~cvcNumber,
~requiresCvv=customerMethod.requiresCvv,
)
| _ => {
let paymentMethodType = switch customerMethod.paymentMethodType {
| Some("")
Expand All @@ -99,8 +107,9 @@ let make = (
)
}
}

if confirm.doSubmit {
if areRequiredFieldsValid && (!isCardPaymentMethod || (complete && !empty)) {
if areRequiredFieldsValid && (!isCardPaymentMethod || isCardPaymentMethodValid) {
intent(
~bodyArr=savedPaymentMethodBody
->Js.Dict.fromArray
Expand Down
18 changes: 18 additions & 0 deletions src/LocaleString.res
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ type localeStrings = {
useExistingPaymentMethods: string,
selectPaymentMethodLabel: string,
savedPaymentMethodsLabel: string,
nicknameLabel: string,
nicknamePlaceholder: string,
}

let defaultLocale = {
Expand Down Expand Up @@ -149,6 +151,8 @@ let defaultLocale = {
useExistingPaymentMethods: "Use saved payment methods",
selectPaymentMethodLabel: "Select Payment Method",
savedPaymentMethodsLabel: "Saved Payment Methods",
nicknameLabel: "Card Nickname",
nicknamePlaceholder: "Card Nickname (Optional)",
}

type locale = {localeStrings: array<localeStrings>}
Expand Down Expand Up @@ -233,6 +237,8 @@ let localeStrings = [
useExistingPaymentMethods: "Use saved payment methods",
selectPaymentMethodLabel: "Select Payment Method",
savedPaymentMethodsLabel: "Saved Payment Methods",
nicknameLabel: "Card Nickname",
nicknamePlaceholder: "Card Nickname (Optional)",
},
{
locale: "he",
Expand Down Expand Up @@ -314,6 +320,8 @@ let localeStrings = [
useExistingPaymentMethods: `השתמש באמצעי תשלום שמורים`,
selectPaymentMethodLabel: `בחר שיטת תשלום`,
savedPaymentMethodsLabel: `אמצעי תשלום שמורים`,
nicknameLabel: `כינוי לכרטיס`,
nicknamePlaceholder: `כינוי לכרטיס (אופציונלי)`,
},
{
locale: `fr`,
Expand Down Expand Up @@ -395,6 +403,8 @@ let localeStrings = [
useExistingPaymentMethods: `Utiliser les modes de paiement enregistrés`,
selectPaymentMethodLabel: `Sélectionnez le mode de paiement`,
savedPaymentMethodsLabel: `Modes de paiement enregistrés`,
nicknameLabel: `Pseudonyme de la carte`,
nicknamePlaceholder: `Surnom de la carte (facultatif)`,
},
{
locale: "en-GB",
Expand Down Expand Up @@ -476,6 +486,8 @@ let localeStrings = [
useExistingPaymentMethods: "Use saved payment methods",
selectPaymentMethodLabel: "Select Payment Method",
savedPaymentMethodsLabel: "Saved Payment Methods",
nicknameLabel: "Card Nickname",
nicknamePlaceholder: "Card Nickname (Optional)",
},
{
locale: "ar",
Expand Down Expand Up @@ -557,6 +569,8 @@ let localeStrings = [
useExistingPaymentMethods: `استخدم طرق الدفع المحفوظة`,
selectPaymentMethodLabel: `اختار طريقة الدفع`,
savedPaymentMethodsLabel: `طرق الدفع المحفوظة`,
nicknameLabel: `الاسم علي الكارت`,
nicknamePlaceholder: `اسم البطاقة (اختياري)`,
},
{
locale: "ja",
Expand Down Expand Up @@ -638,6 +652,8 @@ let localeStrings = [
useExistingPaymentMethods: `保存した支払い方法を使用する`,
selectPaymentMethodLabel: `支払い方法を選択してください`,
savedPaymentMethodsLabel: `保存された支払い方法`,
nicknameLabel: `カードのニックネーム`,
nicknamePlaceholder: `カードニックネーム(任意)`,
},
{
locale: "de",
Expand Down Expand Up @@ -719,5 +735,7 @@ let localeStrings = [
useExistingPaymentMethods: `Gespeicherte Zahlungsarten nutzen`,
selectPaymentMethodLabel: `Wählen Sie die Zahlungsmethode`,
savedPaymentMethodsLabel: `Gespeicherte Zahlungsarten`,
nicknameLabel: `Spitzname der Karte`,
nicknamePlaceholder: `Kartenname (optional)`,
},
]
2 changes: 2 additions & 0 deletions src/Payment.res
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ let make = (~paymentMode, ~integrateError, ~logger) => {
~cardHolderName="",
~cvcNumber,
~cardBrand=cardNetwork,
(),
)
| CardNumberElement =>
let (month, year) = getExpiryDates(getCardElementValue(iframeId, "card-expiry"))
Expand All @@ -263,6 +264,7 @@ let make = (~paymentMode, ~integrateError, ~logger) => {
~cardHolderName="",
~cvcNumber=localCvcNumber,
~cardBrand=cardNetwork,
(),
)
| _ => []
}
Expand Down
25 changes: 23 additions & 2 deletions src/PaymentElement.res
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,19 @@ let make = (
None
}, [savedMethods])

let (walletList, paymentOptionsList, actualList) = React.useMemo4(() => {
let areAllGooglePayRequiredFieldsPrefilled = DynamicFieldsUtils.useAreAllRequiredFieldsPrefilled(
~list,
~paymentMethod="wallet",
~paymentMethodType="google_pay",
)

let areAllApplePayRequiredFieldsPrefilled = DynamicFieldsUtils.useAreAllRequiredFieldsPrefilled(
~list,
~paymentMethod="wallet",
~paymentMethodType="apple_pay",
)

let (walletList, paymentOptionsList, actualList) = React.useMemo6(() => {
switch methodslist {
| Loaded(paymentlist) =>
let paymentOrder =
Expand All @@ -119,6 +131,8 @@ let make = (
~order=paymentOrder,
~showApplePay=isApplePayReady,
~showGooglePay=isGooglePayReady,
~areAllGooglePayRequiredFieldsPrefilled,
~areAllApplePayRequiredFieldsPrefilled,
)
(
wallets->Utils.removeDuplicate,
Expand All @@ -131,7 +145,14 @@ let make = (
: ([], [], [])
| _ => ([], [], [])
}
}, (methodslist, paymentMethodOrder, isApplePayReady, isGooglePayReady))
}, (
methodslist,
paymentMethodOrder,
isApplePayReady,
isGooglePayReady,
areAllGooglePayRequiredFieldsPrefilled,
areAllApplePayRequiredFieldsPrefilled,
))

React.useEffect4(() => {
switch methodslist {
Expand Down
43 changes: 32 additions & 11 deletions src/Payments/CardPayment.res
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ let make = (
let {config, themeObj, localeString} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom)
let options = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom)
let loggerState = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom)

let (nickname, setNickname) = React.useState(_ => "")

let (
isCardValid,
setIsCardValid,
Expand Down Expand Up @@ -100,7 +103,15 @@ let make = (
~isCvcValidValue,
)

let submitCallback = React.useCallback5((ev: Window.event) => {
let isCustomerAcceptanceRequired = React.useMemo1(() => {
if displaySavedPaymentMethodsCheckbox {
isSaveCardsChecked || list.payment_type === SETUP_MANDATE
} else {
!(isGuestCustomer || list.payment_type === NORMAL)
}
}, [isSaveCardsChecked])

let submitCallback = React.useCallback6((ev: Window.event) => {
let json = ev.data->Js.Json.parseExn
let confirm = json->getDictFromJson->ConfirmType.itemToObjMapper
let (month, year) = CardUtils.getExpiryDates(cardExpiry)
Expand All @@ -120,18 +131,14 @@ let make = (
~cardHolderName="",
~cvcNumber,
~cardBrand=cardNetwork,
~nickname,
(),
)
let banContactBody = PaymentBody.bancontactBody()
let cardBody = if displaySavedPaymentMethodsCheckbox {
if isSaveCardsChecked || list.payment_type === SETUP_MANDATE {
defaultCardBody->Js.Array2.concat(onSessionBody)
} else {
defaultCardBody
}
} else if isGuestCustomer || list.payment_type === NORMAL {
defaultCardBody
} else {
let cardBody = if isCustomerAcceptanceRequired {
defaultCardBody->Js.Array2.concat(onSessionBody)
} else {
defaultCardBody
}
if confirm.doSubmit {
let validFormat =
Expand Down Expand Up @@ -171,7 +178,14 @@ let make = (
}
}
}
}, (areRequiredFieldsValid, requiredFieldsBody, empty, complete, isSaveCardsChecked))
}, (
areRequiredFieldsValid,
requiredFieldsBody,
empty,
complete,
isCustomerAcceptanceRequired,
nickname,
))
submitPaymentData(submitCallback)

let paymentMethod = isBancontact ? "bank_redirect" : "card"
Expand All @@ -182,6 +196,8 @@ let make = (
options.displaySavedPaymentMethodsCheckbox &&
!isBancontact

let nicknameFieldClassName = conditionsForShowingSaveCardCheckbox ? "pt-2" : "pt-5"

<div className="animate-slowShow">
<RenderIf condition={showFields || isBancontact}>
<div
Expand Down Expand Up @@ -271,6 +287,11 @@ let make = (
<AnimatedCheckbox isChecked=isSaveCardsChecked setIsChecked=setIsSaveCardsChecked />
</div>
</RenderIf>
<RenderIf condition={isCustomerAcceptanceRequired}>
<div className={`pb-2 ${nicknameFieldClassName}`}>
<NicknamePaymentInput paymentType value=nickname setValue=setNickname />
</div>
</RenderIf>
<RenderIf
condition={options.displaySavedPaymentMethods &&
savedMethods->Array.length > 0 &&
Expand Down
7 changes: 7 additions & 0 deletions src/Types/PaymentType.res
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ type customerCard = {
expiryYear: string,
cardToken: string,
cardHolderName: option<string>,
nickname: string,
}
type customerMethods = {
paymentToken: string,
Expand All @@ -123,6 +124,7 @@ type customerMethods = {
card: customerCard,
paymentMethodType: option<string>,
defaultPaymentMethodSet: bool,
requiresCvv: bool,
}
type savedCardsLoadState =
LoadingSavedCards | LoadedSavedCards(array<customerMethods>, bool) | NoResult(bool)
Expand Down Expand Up @@ -164,6 +166,7 @@ let defaultCardDetails = {
expiryYear: "",
cardToken: "",
cardHolderName: None,
nickname: "",
}
let defaultCustomerMethods = {
paymentToken: "",
Expand All @@ -173,6 +176,7 @@ let defaultCustomerMethods = {
card: defaultCardDetails,
paymentMethodType: None,
defaultPaymentMethodSet: false,
requiresCvv: true,
}
let defaultLayout = {
defaultCollapsed: false,
Expand Down Expand Up @@ -780,6 +784,7 @@ let getCardDetails = (dict, str) => {
expiryYear: getString(json, "expiry_year", ""),
cardToken: getString(json, "card_token", ""),
cardHolderName: Some(getString(json, "card_holder_name", "")),
nickname: getString(json, "nick_name", ""),
}
})
->Belt.Option.getWithDefault(defaultCardDetails)
Expand Down Expand Up @@ -820,6 +825,7 @@ let createCustomerObjArr = dict => {
card: getCardDetails(dict, "card"),
paymentMethodType: getPaymentMethodType(dict),
defaultPaymentMethodSet: getBool(dict, "default_payment_method_set", false),
requiresCvv: getBool(dict, "requires_cvv", true),
}
})
LoadedSavedCards(customerPaymentMethods, isGuestCustomer)
Expand All @@ -842,6 +848,7 @@ let getCustomerMethods = (dict, str) => {
card: getCardDetails(json, "card"),
paymentMethodType: getPaymentMethodType(dict),
defaultPaymentMethodSet: getBool(dict, "default_payment_method_set", false),
requiresCvv: getBool(dict, "requires_cvv", true),
}
})
LoadedSavedCards(customerPaymentMethods, false)
Expand Down
Loading
Loading