Skip to content

Commit

Permalink
feat: added One Click Widgets (ApplePay, GooglePay, PayPal)
Browse files Browse the repository at this point in the history
  • Loading branch information
ArushKapoorJuspay committed Apr 8, 2024
1 parent ce71d4b commit 85b3581
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 8 deletions.
3 changes: 3 additions & 0 deletions src/CardTheme.res
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ let getPaymentMode = val => {
| "cardNumber" => CardNumberElement
| "cardExpiry" => CardExpiryElement
| "cardCvc" => CardCVCElement
| "googlePay" => GooglePayElement
| "payPal" => PayPalElement
| "applePay" => ApplePayElement
| _ => NONE
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/CardUtils.res
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,9 @@ let getCardBrandIcon = (cardType, paymentType) => {
| CardNumberElement
| CardExpiryElement
| CardCVCElement
| GooglePayElement
| PayPalElement
| ApplePayElement
| NONE =>
<Icon size=brandIconSize name="default-card" />
}
Expand Down
3 changes: 3 additions & 0 deletions src/LoaderController.res
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime
| CardCVCElement
| Card =>
setOptions(_ => ElementType.itemToObjMapper(optionsDict, logger))
| GooglePayElement
| PayPalElement
| ApplePayElement
| Payment => {
let paymentOptions = PaymentType.itemToObjMapper(optionsDict, logger)
setOptionsPayment(_ => paymentOptions)
Expand Down
9 changes: 7 additions & 2 deletions src/PaymentElementRenderer.res
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ let make = (
switch (sessions, list) {
| (_, Loading) =>
<RenderIf condition=showLoader>
<PaymentElementShimmer />
{paymentType->Utils.isWalletElementPaymentType
? <WalletShimmer />
: <PaymentElementShimmer />}
</RenderIf>
| _ => <PaymentElement cardProps expiryProps cvcProps countryProps paymentType />
| _ =>
paymentType->Utils.isWalletElementPaymentType
? <WalletElementRenderer paymentType />
: <PaymentElement cardProps expiryProps cvcProps countryProps paymentType />
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/RenderPaymentMethods.res
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,15 @@ let make = (
paymentType cardProps expiryProps cvcProps zipProps handleElementFocus isFocus
/>
</React.Suspense>
| GooglePayElement
| PayPalElement
| ApplePayElement
| Payment =>
<React.Suspense
fallback={<RenderIf condition={showLoader}>
<PaymentElementShimmer />
{paymentType->Utils.isWalletElementPaymentType
? <WalletShimmer />
: <PaymentElementShimmer />}
</RenderIf>}>
<PaymentElementRendererLazy paymentType cardProps expiryProps cvcProps countryProps />
</React.Suspense>
Expand Down
3 changes: 3 additions & 0 deletions src/Types/CardThemeType.res
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ type mode =
| CardNumberElement
| CardExpiryElement
| CardCVCElement
| GooglePayElement
| PayPalElement
| ApplePayElement
| NONE
type label = Above | Floating | Never
type themeClass = {
Expand Down
25 changes: 25 additions & 0 deletions src/Utilities/Utils.res
Original file line number Diff line number Diff line change
Expand Up @@ -1234,3 +1234,28 @@ let makeOneClickHandlerPromise = sdkHandleOneClickConfirmPayment => {
}
})
}

let getWalletPaymentMethod = (wallets, paymentType: CardThemeType.mode) => {
switch paymentType {
| GooglePayElement => wallets->Js.Array2.filter(item => item === "google_pay")
| PayPalElement => wallets->Js.Array2.filter(item => item === "paypal")
| ApplePayElement => wallets->Js.Array2.filter(item => item === "apple_pay")
| _ => wallets
}
}

let isComponentTypeForPaymentElementCreate = componentType => {
componentType === "payment" ||
componentType === "googlePay" ||
componentType === "payPal" ||
componentType === "applePay"
}

let isWalletElementPaymentType = (paymentType: CardThemeType.mode) => {
switch paymentType {
| GooglePayElement
| PayPalElement
| ApplePayElement => true
| _ => false
}
}
81 changes: 81 additions & 0 deletions src/WalletElementRenderer.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
open PaymentType
open RecoilAtoms

@react.component
let make = (~paymentType: CardThemeType.mode) => {
let sessionsObj = Recoil.useRecoilValueFromAtom(sessions)
let {paymentMethodOrder} = Recoil.useRecoilValueFromAtom(optionAtom)
let isApplePayReady = Recoil.useRecoilValueFromAtom(isApplePayReady)
let isGooglePayReady = Recoil.useRecoilValueFromAtom(isGooglePayReady)
let methodslist = Recoil.useRecoilValueFromAtom(list)
let paymentOrder = paymentMethodOrder->Utils.getOptionalArr->Utils.removeDuplicate
let (sessions, setSessions) = React.useState(_ => Dict.make()->JSON.Encode.object)
let (walletOptions, setWalletOptions) = React.useState(_ => [])

let (list, setList) = React.useState(_ => PaymentMethodsRecord.defaultList)

let areAllGooglePayRequiredFieldsPrefilled = DynamicFieldsUtils.useAreAllRequiredFieldsPrefilled(
~list,
~paymentMethod="wallet",
~paymentMethodType="google_pay",
)

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

let walletList = React.useMemo(() => {
switch methodslist {
| Loaded(paymentlist) =>
let paymentOrder =
paymentOrder->Array.length > 0 ? paymentOrder : PaymentModeType.defaultOrder
let plist = paymentlist->Utils.getDictFromJson->PaymentMethodsRecord.itemToObjMapper
let (wallets, _) =
plist->PaymentUtils.paymentListLookupNew(
~order=paymentOrder,
~showApplePay=isApplePayReady,
~showGooglePay=isGooglePayReady,
~areAllGooglePayRequiredFieldsPrefilled,
~areAllApplePayRequiredFieldsPrefilled,
)
wallets->Utils.removeDuplicate->Utils.getWalletPaymentMethod(paymentType)
| _ => []
}
}, (
methodslist,
paymentMethodOrder,
isApplePayReady,
isGooglePayReady,
areAllGooglePayRequiredFieldsPrefilled,
areAllApplePayRequiredFieldsPrefilled,
))

React.useEffect(() => {
switch methodslist {
| Loaded(paymentlist) =>
let plist = paymentlist->Utils.getDictFromJson->PaymentMethodsRecord.itemToObjMapper

setWalletOptions(_ => walletList)
setList(_ => plist)
| _ => ()
}
None
}, (methodslist, walletList))
React.useEffect(() => {
switch sessionsObj {
| Loaded(ssn) => setSessions(_ => ssn)
| _ => ()
}
None
}, [sessionsObj])

<RenderIf condition={walletOptions->Array.length > 0}>
<div className="flex flex-col place-items-center">
<ErrorBoundary key="payment_request_buttons_all" level={ErrorBoundary.RequestButton}>
<PaymentRequestButtonElement sessions walletOptions list />
</ErrorBoundary>
</div>
</RenderIf>
}
18 changes: 15 additions & 3 deletions src/orca-loader/Elements.res
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ let make = (
| "cardNumber"
| "cardExpiry"
| "cardCvc"
| "googlePay"
| "payPal"
| "applePay"
| "payment" => ()
| str => manageErrorWarning(UNKNOWN_KEY, ~dynamicStr=`${str} type in create`, ~logger, ())
}
Expand All @@ -235,7 +238,10 @@ let make = (
->JSON.Encode.object
let message =
[
("paymentElementCreate", (componentType == "payment")->JSON.Encode.bool),
(
"paymentElementCreate",
componentType->Utils.isComponentTypeForPaymentElementCreate->JSON.Encode.bool,
),
("otherElements", otherElements->JSON.Encode.bool),
("options", newOptions),
("componentType", componentType->JSON.Encode.string),
Expand Down Expand Up @@ -440,7 +446,10 @@ let make = (
})
->then(res => {
let (json, applePayPresent, googlePayPresent) = res
if componentType === "payment" && applePayPresent->Option.isSome {
if (
componentType->Utils.isComponentTypeForPaymentElementCreate &&
applePayPresent->Option.isSome
) {
//do operations here
let processPayment = (token: JSON.t) => {
//let body = PaymentBody.applePayBody(~token)
Expand Down Expand Up @@ -639,7 +648,10 @@ let make = (

addSmartEventListener("message", handleApplePayMessages.contents, "onApplePayMessages")
}
if componentType === "payment" && googlePayPresent->Option.isSome {
if (
componentType->Utils.isComponentTypeForPaymentElementCreate &&
googlePayPresent->Option.isSome
) {
let dict = json->getDictFromJson
let sessionObj = SessionsType.itemToObjMapper(dict, Others)
let gPayToken = SessionsType.getPaymentSessionObj(sessionObj.sessionsToken, Gpay)
Expand Down
4 changes: 2 additions & 2 deletions src/orca-loader/LoaderPaymentElement.res
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,10 @@ let make = (componentType, options, setIframeRef, iframeRef, mountPostMessage) =

let oElement = Window.querySelector(selector)
let classesBase = optionsDict->getClasses("base")
let additionalIframeStyle = componentType->Utils.isOtherElements ? "height: 2rem;" : ""
let additionalIframeStyle = componentType->Utils.isOtherElements ? "height: 2rem;" : "height: 0;"
switch oElement->Nullable.toOption {
| Some(elem) => {
let iframeDiv = `<div id="orca-element-${localSelectorString}" style= "height: auto;" class="${componentType} ${currentClass.contents} ${classesBase} ">
let iframeDiv = `<div id="orca-element-${localSelectorString}" style="height: auto;" class="${componentType} ${currentClass.contents} ${classesBase}">
<div id="orca-fullscreen-iframeRef-${localSelectorString}"></div>
<iframe
id ="orca-payment-element-iframeRef-${localSelectorString}"
Expand Down

0 comments on commit 85b3581

Please sign in to comment.