Skip to content

Commit

Permalink
feat: add address element for shipping and billing address
Browse files Browse the repository at this point in the history
  • Loading branch information
aritro2002 committed Dec 3, 2024
1 parent bf64610 commit a81387a
Show file tree
Hide file tree
Showing 17 changed files with 525 additions and 7 deletions.
403 changes: 403 additions & 0 deletions src/AddressElement.res

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/CardUtils.res
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ let getCardBrandIcon = (cardType, paymentType) => {
| ExpressCheckoutElement
| PaymentMethodsManagement
| PazeElement
| ShippingAddressElement
| BillingAddressElement
| NONE =>
<Icon size=brandIconSize name="default-card" />
}
Expand Down
4 changes: 2 additions & 2 deletions src/Components/EmailPaymentInput.res
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ open PaymentType
open Utils

@react.component
let make = (~paymentType) => {
let make = (~paymentType, ~isOptional=false) => {
let {localeString} = Recoil.useRecoilValueFromAtom(configAtom)
let loggerState = Recoil.useRecoilValueFromAtom(loggerAtom)
let (email, setEmail) = Recoil.useLoggedRecoilState(userEmailAddress, "email", loggerState)
Expand Down Expand Up @@ -56,7 +56,7 @@ let make = (~paymentType) => {

<RenderIf condition={showDetails.email == Auto}>
<PaymentField
fieldName=localeString.emailLabel
fieldName={localeString.emailLabel ++ (isOptional ? " (Optional)" : "")}
setValue={setEmail}
value=email
onChange=changeEmail
Expand Down
9 changes: 7 additions & 2 deletions src/Components/FullNamePaymentInput.res
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ open PaymentType
open Utils

@react.component
let make = (~paymentType, ~customFieldName=None, ~optionalRequiredFields=None) => {
let make = (
~paymentType,
~customFieldName=None,
~optionalRequiredFields=None,
~isOptional=false,
) => {
let {localeString} = Recoil.useRecoilValueFromAtom(configAtom)
let {fields} = Recoil.useRecoilValueFromAtom(optionAtom)
let loggerState = Recoil.useRecoilValueFromAtom(loggerAtom)
Expand Down Expand Up @@ -79,7 +84,7 @@ let make = (~paymentType, ~customFieldName=None, ~optionalRequiredFields=None) =

<RenderIf condition={showDetails.name == Auto}>
<PaymentField
fieldName
fieldName={fieldName ++ (isOptional ? " (Optional)" : "")}
setValue=setFullName
value=fullName
onChange=changeName
Expand Down
4 changes: 3 additions & 1 deletion src/Components/InputField.res
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ let make = (
| CardCVCElement
| CardExpiryElement
| CardNumberElement
| PaymentMethodCollectElement =>
| PaymentMethodCollectElement
| ShippingAddressElement
| BillingAddressElement =>
setEleClassName(_ => val)
| _ => ()
}
Expand Down
6 changes: 4 additions & 2 deletions src/Components/PhoneNumberPaymentInput.res
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@react.component
let make = () => {
let make = (~isOptional=false) => {
open RecoilAtoms
open PaymentType
open Utils
Expand Down Expand Up @@ -59,13 +59,15 @@ let make = () => {
...prev,
countryCode: valueDropDown->getCountryCodeSplitValue,
value: val,
errorString: val === "" ? prev.errorString : "",
})
}

React.useEffect(() => {
setPhone(prev => {
...prev,
countryCode: valueDropDown->getCountryCodeSplitValue,
errorString: prev.value === "" ? prev.errorString : "",
})
None
}, [valueDropDown])
Expand All @@ -85,7 +87,7 @@ let make = () => {

<RenderIf condition={showDetails.phone == Auto}>
<PaymentField
fieldName="Phone Number"
fieldName={"Phone Number" ++ (isOptional ? " (Optional)" : "")}
value=phone
onChange=changePhone
paymentType=Payment
Expand Down
10 changes: 10 additions & 0 deletions src/Country.res
Original file line number Diff line number Diff line change
Expand Up @@ -1697,3 +1697,13 @@ let getCountry = paymentMethodName => {
| _ => country
}
}

let getCountryNameFromIsoAlpha = (code: string): string => {
let upperCode = code->Js.String2.toUpperCase
switch country->Array.find(ele => {
ele.isoAlpha2 == upperCode || ele.isoAlpha3 == upperCode
}) {
| Some(val) => val.countryName
| None => "India"
}
}
6 changes: 6 additions & 0 deletions src/LoaderController.res
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime
let setIsPaymentButtonHandlerProvided = Recoil.useSetRecoilState(
isPaymentButtonHandlerProvidedAtom,
)
let setAddressElementOptions = Recoil.useSetRecoilState(addressElementOptions)

let optionsCallback = (optionsPayment: PaymentType.options) => {
[
Expand Down Expand Up @@ -94,6 +95,11 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime
)
setPaymentMethodCollectOptions(_ => paymentMethodCollectOptions)
}
| ShippingAddressElement
| BillingAddressElement => {
let addressOptions = PaymentType.itemToObjMapperAddress(optionsDict, logger)
setAddressElementOptions(_ => addressOptions)
}
| GooglePayElement
| PayPalElement
| ApplePayElement
Expand Down
2 changes: 2 additions & 0 deletions src/RenderPaymentMethods.res
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ let make = (
paymentType cardProps expiryProps cvcProps zipProps handleElementFocus isFocus
/>
</ReusableReactSuspense>
| ShippingAddressElement => <AddressElement mode="shipping" />
| BillingAddressElement => <AddressElement mode="billing" />
| GooglePayElement
| PayPalElement
| ApplePayElement
Expand Down
4 changes: 4 additions & 0 deletions src/Types/CardThemeType.res
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type mode =
| PazeElement
| ExpressCheckoutElement
| PaymentMethodsManagement
| ShippingAddressElement
| BillingAddressElement
| NONE
type label = Above | Floating | Never
type themeClass = {
Expand Down Expand Up @@ -110,6 +112,8 @@ let getPaymentMode = val => {
| "expressCheckout" => ExpressCheckoutElement
| "paze" => PazeElement
| "paymentMethodsManagement" => PaymentMethodsManagement
| "shippingAddressElement" => ShippingAddressElement
| "billingAddressElement" => BillingAddressElement
| _ => NONE
}
}
Expand Down
33 changes: 33 additions & 0 deletions src/Types/PaymentType.res
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,26 @@ type address = {
country: string,
postal_code: string,
}

type addressDetails = {
first_name: string,
last_name: string,
line1: string,
line2: string,
city: string,
state: string,
country: string,
postal_code: string,
email: string,
phone: string,
country_code: string,
}

type addressData = {
complete: bool,
data: addressDetails,
}

type addressType =
| JSONString(string)
| JSONObject(showAddress)
Expand Down Expand Up @@ -185,6 +205,8 @@ type payerDetails = {
phone: option<string>,
}

type addressOptions = {optional: array<string>}

let defaultCardDetails = {
scheme: None,
last4Digits: "",
Expand Down Expand Up @@ -327,6 +349,11 @@ let defaultOptions = {
customMessageForCardTerms: "",
}

let defaultOptional = []
let defaultAddressOptions = {
optional: defaultOptional,
}

let getLayout = (str, logger) => {
switch str {
| "tabs" => Tabs
Expand Down Expand Up @@ -1090,3 +1117,9 @@ let itemToPayerDetailsObjectMapper = dict => {
->Option.flatMap(Dict.get(_, "national_number"))
->Option.flatMap(JSON.Decode.string),
}

let itemToObjMapperAddress = (dict, logger) => {
{
optional: getStrArray(dict, "optional"),
}
}
1 change: 1 addition & 0 deletions src/Utilities/RecoilAtoms.res
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ let keys = Recoil.atom("keys", CommonHooks.defaultkeys)
let configAtom = Recoil.atom("defaultRecoilConfig", CardTheme.defaultRecoilConfig)
let portalNodes = Recoil.atom("portalNodes", PortalState.defaultDict)
let elementOptions = Recoil.atom("elementOptions", ElementType.defaultOptions)
let addressElementOptions = Recoil.atom("addressElementOptions", PaymentType.defaultAddressOptions)
let optionAtom = Recoil.atom("options", PaymentType.defaultOptions)
let sessions = Recoil.atom("sessions", PaymentType.Loading)
let paymentMethodList = Recoil.atom("paymentMethodList", PaymentType.Loading)
Expand Down
2 changes: 2 additions & 0 deletions src/Utilities/Utils.res
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,8 @@ let expressCheckoutComponents = [
"paze",
"samsungPay",
"expressCheckout",
"shippingAddressElement",
"billingAddressElement",
]

let spmComponents = ["paymentMethodCollect"]->Array.concat(expressCheckoutComponents)
Expand Down
2 changes: 2 additions & 0 deletions src/Window.res
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ external removeEventListener: (string, 'ev => unit) => unit = "removeEventListen
@scope("window") @get external cardNumberElement: window => option<window> = "cardNumber"
@get external cardCVCElement: window => option<window> = "cardCvc"
@get external cardExpiryElement: window => option<window> = "cardExpiry"
@get external shippingAddressElement: window => option<window> = "shippingAddressElement"
@get external billingAddressElement: window => option<window> = "billingAddressElement"
@get external document: window => document = "document"
@get external fullscreen: window => option<window> = "fullscreen"
@get external frames: window => {..} = "frames"
Expand Down
2 changes: 2 additions & 0 deletions src/hyper-loader/Elements.res
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ let make = (
| "paze"
| "samsungPay"
| "paymentMethodsManagement"
| "shippingAddressElement"
| "billingAddressElement"
| "payment" => ()
| str => manageErrorWarning(UNKNOWN_KEY, ~dynamicStr=`${str} type in create`, ~logger)
}
Expand Down
40 changes: 40 additions & 0 deletions src/hyper-loader/LoaderPaymentElement.res
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,45 @@ let make = (
})
}

let getAddressValues = () => {
Promise.make((resolve, _reject) => {
if componentType !== "billingAddressElement" && componentType !== "shippingAddressElement" {
resolve(JSON.Encode.null)
}

iframeRef->Array.forEach(iframe => {
if componentType === "billingAddressElement" {
let message = [("getBillingAddress", true->JSON.Encode.bool)]->Dict.fromArray
iframe->Window.iframePostMessage(message)
} else {
let message = [("getShippingAddress", true->JSON.Encode.bool)]->Dict.fromArray
iframe->Window.iframePostMessage(message)
}
})

let handleFun = (ev: Types.event) => {
let json = ev.data->anyTypeToJson
let dict = json->Utils.getDictFromJson

if (
dict->Dict.get("billingAddressDetails")->Option.isSome &&
componentType === "billingAddressElement"
) {
let addressDetails = dict->Utils.getDictFromDict("billingAddressDetails")
resolve(addressDetails->Identity.anyTypeToJson)
} else if (
dict->Dict.get("shippingAddressDetails")->Option.isSome &&
componentType === "shippingAddressElement"
) {
let addressDetails = dict->Utils.getDictFromDict("shippingAddressDetails")
resolve(addressDetails->Identity.anyTypeToJson)
}
}

addSmartEventListener("message", handleFun, "showAddressHandler")->ignore
})
}

let focus = () => {
iframeRef->Array.forEach(iframe => {
let message = [("doFocus", true->JSON.Encode.bool)]->Dict.fromArray
Expand Down Expand Up @@ -420,6 +459,7 @@ let make = (
update,
mount,
onSDKHandleClick,
getAddressValues,
}
} catch {
| e => {
Expand Down
2 changes: 2 additions & 0 deletions src/hyper-loader/Types.res
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type paymentElement = {
focus: unit => unit,
clear: unit => unit,
onSDKHandleClick: option<unit => Promise.t<unit>> => unit,
getAddressValues: unit => Promise.t<JSON.t>,
}

type element = {
Expand Down Expand Up @@ -121,6 +122,7 @@ let defaultPaymentElement = {
focus: () => (),
clear: () => (),
onSDKHandleClick: fnArgument => (),
getAddressValues: () => Promise.make((resolve, _) => resolve(Dict.make()->JSON.Encode.object)),
}

let create = (_componentType, _options) => {
Expand Down

0 comments on commit a81387a

Please sign in to comment.