Skip to content

Commit

Permalink
feat: added click handler (#732)
Browse files Browse the repository at this point in the history
  • Loading branch information
sakksham7 authored Oct 15, 2024
1 parent 5c08f66 commit 9c09ff2
Show file tree
Hide file tree
Showing 13 changed files with 126 additions and 52 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2370,4 +2370,4 @@

### Features

* updated Readme ([427f8fd](https://github.com/juspay/hyperswitch-web/commit/427f8fd91be58fc63b0fa4ab326d562a4caaabab))
* updated Readme ([427f8fd](https://github.com/juspay/hyperswitch-web/commit/427f8fd91be58fc63b0fa4ab326d562a4caaabab))
8 changes: 8 additions & 0 deletions src/LoaderController.res
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime
let (isCompleteCallbackUsed, setIsCompleteCallbackUsed) = Recoil.useRecoilState(
isCompleteCallbackUsed,
)
let (isPaymentButtonHandlerProvided, setIsPaymentButtonHandlerProvided) = Recoil.useRecoilState(
isPaymentButtonHandlerProvidedAtom,
)

let optionsCallback = (optionsPayment: PaymentType.options) => {
[
Expand Down Expand Up @@ -248,10 +251,15 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime
let metadata = dict->getJsonObjectFromDict("analyticsMetadata")
logger.setMetadata(metadata)
}

if dict->getDictIsSome("onCompleteDoThisUsed") {
let isCallbackUsedVal = dict->Utils.getBool("onCompleteDoThisUsed", false)
setIsCompleteCallbackUsed(_ => isCallbackUsedVal)
}
if dict->getDictIsSome("isPaymentButtonHandlerProvided") {
let isSDKClick = dict->Utils.getBool("isPaymentButtonHandlerProvided", false)
setIsPaymentButtonHandlerProvided(_ => isSDKClick)
}
if dict->getDictIsSome("paymentOptions") {
let paymentOptions = dict->getDictFromObj("paymentOptions")

Expand Down
13 changes: 9 additions & 4 deletions src/Payments/ApplePay.res
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ let make = (~sessionObj: option<JSON.t>, ~walletOptions, ~paymentType: CardTheme
let url = RescriptReactRouter.useUrl()
let componentName = CardUtils.getQueryParamsDictforKey(url.search, "componentName")
let loggerState = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom)
let {publishableKey, sdkHandleOneClickConfirmPayment} = Recoil.useRecoilValueFromAtom(
RecoilAtoms.keys,
let sdkHandleIsThere = Recoil.useRecoilValueFromAtom(
RecoilAtoms.isPaymentButtonHandlerProvidedAtom,
)
let {publishableKey} = Recoil.useRecoilValueFromAtom(RecoilAtoms.keys)
let isApplePayReady = Recoil.useRecoilValueFromAtom(RecoilAtoms.isApplePayReady)
let setIsShowOrPayUsing = Recoil.useSetRecoilState(RecoilAtoms.isShowOrPayUsing)
let (showApplePay, setShowApplePay) = React.useState(() => false)
Expand Down Expand Up @@ -212,7 +213,7 @@ let make = (~sessionObj: option<JSON.t>, ~walletOptions, ~paymentType: CardTheme
~paymentMethod="APPLE_PAY",
)
setApplePayClicked(_ => true)
makeOneClickHandlerPromise(sdkHandleOneClickConfirmPayment)
makeOneClickHandlerPromise(sdkHandleIsThere)
->then(result => {
let result = result->JSON.Decode.bool->Option.getOr(false)
if result {
Expand Down Expand Up @@ -241,7 +242,11 @@ let make = (~sessionObj: option<JSON.t>, ~walletOptions, ~paymentType: CardTheme
~isManualRetryEnabled,
)
} else {
ApplePayHelpers.handleApplePayButtonClicked(~sessionObj, ~componentName, ~paymentMethodListValue)
ApplePayHelpers.handleApplePayButtonClicked(
~sessionObj,
~componentName,
~paymentMethodListValue,
)
}
} else {
let bodyDict = PaymentBody.applePayRedirectBody(~connectors)
Expand Down
5 changes: 3 additions & 2 deletions src/Payments/GPay.res
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ let make = (
let componentName = CardUtils.getQueryParamsDictforKey(url.search, "componentName")
let loggerState = Recoil.useRecoilValueFromAtom(loggerAtom)
let {iframeId} = Recoil.useRecoilValueFromAtom(keys)
let {publishableKey, sdkHandleOneClickConfirmPayment} = Recoil.useRecoilValueFromAtom(keys)
let isSDKHandleClick = Recoil.useRecoilValueFromAtom(isPaymentButtonHandlerProvidedAtom)
let {publishableKey} = Recoil.useRecoilValueFromAtom(keys)
let options = Recoil.useRecoilValueFromAtom(optionAtom)
let intent = PaymentHelpers.usePaymentIntent(Some(loggerState), Gpay)
let isManualRetryEnabled = Recoil.useRecoilValueFromAtom(RecoilAtoms.isManualRetryEnabled)
Expand Down Expand Up @@ -103,7 +104,7 @@ let make = (
~eventName=GOOGLE_PAY_FLOW,
~paymentMethod="GOOGLE_PAY",
)
makeOneClickHandlerPromise(sdkHandleOneClickConfirmPayment)->then(result => {
makeOneClickHandlerPromise(isSDKHandleClick)->then(result => {
let result = result->JSON.Decode.bool->Option.getOr(false)
if result {
if isInvokeSDKFlow {
Expand Down
11 changes: 6 additions & 5 deletions src/Payments/KlarnaSDK.res
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ open KlarnaSDKTypes
let make = (~sessionObj: SessionsType.token) => {
let url = RescriptReactRouter.useUrl()
let componentName = CardUtils.getQueryParamsDictforKey(url.search, "componentName")
let loggerState = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom)
let setIsShowOrPayUsing = Recoil.useSetRecoilState(RecoilAtoms.isShowOrPayUsing)
let {publishableKey, sdkHandleOneClickConfirmPayment} = Recoil.useRecoilValueFromAtom(keys)
let loggerState = Recoil.useRecoilValueFromAtom(loggerAtom)
let setIsShowOrPayUsing = Recoil.useSetRecoilState(isShowOrPayUsing)
let sdkHandleIsThere = Recoil.useRecoilValueFromAtom(isPaymentButtonHandlerProvidedAtom)
let {publishableKey} = Recoil.useRecoilValueFromAtom(keys)
let options = Recoil.useRecoilValueFromAtom(optionAtom)
let isManualRetryEnabled = Recoil.useRecoilValueFromAtom(RecoilAtoms.isManualRetryEnabled)
let isManualRetryEnabled = Recoil.useRecoilValueFromAtom(isManualRetryEnabled)
let intent = PaymentHelpers.usePaymentIntent(Some(loggerState), Other)
let {iframeId} = Recoil.useRecoilValueFromAtom(keys)
let status = CommonHooks.useScript("https://x.klarnacdn.net/kp/lib/v1/api.js") // Klarna SDK script
Expand Down Expand Up @@ -65,7 +66,7 @@ let make = (~sessionObj: SessionsType.token) => {
theme: options.wallets.style.theme == Dark ? "default" : "outlined",
shape: "default",
on_click: authorize => {
makeOneClickHandlerPromise(sdkHandleOneClickConfirmPayment)->then(
makeOneClickHandlerPromise(sdkHandleIsThere)->then(
result => {
let result = result->JSON.Decode.bool->Option.getOr(false)
if result {
Expand Down
5 changes: 3 additions & 2 deletions src/Payments/PayPal.res
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ let payPalIcon = <Icon size=35 width=90 name="paypal" />
let make = () => {
let loggerState = Recoil.useRecoilValueFromAtom(loggerAtom)
let (paypalClicked, setPaypalClicked) = React.useState(_ => false)
let {publishableKey, sdkHandleOneClickConfirmPayment} = Recoil.useRecoilValueFromAtom(keys)
let sdkHandleIsThere = Recoil.useRecoilValueFromAtom(isPaymentButtonHandlerProvidedAtom)
let {publishableKey} = Recoil.useRecoilValueFromAtom(keys)
let options = Recoil.useRecoilValueFromAtom(optionAtom)
let areOneClickWalletsRendered = Recoil.useSetRecoilState(areOneClickWalletsRendered)
let paymentMethodListValue = Recoil.useRecoilValueFromAtom(PaymentUtils.paymentMethodListValue)
Expand Down Expand Up @@ -48,7 +49,7 @@ let make = () => {
)
setPaypalClicked(_ => true)
open Promise
Utils.makeOneClickHandlerPromise(sdkHandleOneClickConfirmPayment)
Utils.makeOneClickHandlerPromise(sdkHandleIsThere)
->then(result => {
let result = result->JSON.Decode.bool->Option.getOr(false)
if result {
Expand Down
4 changes: 4 additions & 0 deletions src/Payments/PaypalSDK.res
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ let make = (~sessionObj: SessionsType.token, ~paymentType: CardThemeType.mode) =
let {iframeId, publishableKey, sdkHandleOneClickConfirmPayment} = Recoil.useRecoilValueFromAtom(
RecoilAtoms.keys,
)
let sdkHandleIsThere = Recoil.useRecoilValueFromAtom(
RecoilAtoms.isPaymentButtonHandlerProvidedAtom,
)
let (loggerState, _setLoggerState) = Recoil.useRecoilState(RecoilAtoms.loggerAtom)
let areOneClickWalletsRendered = Recoil.useSetRecoilState(RecoilAtoms.areOneClickWalletsRendered)
let paymentMethodListValue = Recoil.useRecoilValueFromAtom(PaymentUtils.paymentMethodListValue)
Expand Down Expand Up @@ -92,6 +95,7 @@ let make = (~sessionObj: SessionsType.token, ~paymentType: CardThemeType.mode) =
~areOneClickWalletsRendered,
~setIsCompleted,
~isCallbackUsedVal,
~sdkHandleIsThere,
)
})
Window.body->Window.appendChild(paypalScript)
Expand Down
3 changes: 2 additions & 1 deletion src/Payments/PaypalSDKHelpers.res
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ let loadPaypalSDK = (
) => unit,
~setIsCompleted,
~isCallbackUsedVal: bool,
~sdkHandleIsThere: bool,
) => {
loggerState.setLogInfo(
~value="Paypal SDK Button Clicked",
Expand All @@ -34,7 +35,7 @@ let loadPaypalSDK = (
style: buttonStyle,
fundingSource: paypal["FUNDING"]["PAYPAL"],
createOrder: () => {
Utils.makeOneClickHandlerPromise(sdkHandleOneClickConfirmPayment)->then(result => {
Utils.makeOneClickHandlerPromise(sdkHandleIsThere)->then(result => {
let result = result->JSON.Decode.bool->Option.getOr(false)
if result {
Utils.messageParentWindow([
Expand Down
1 change: 1 addition & 0 deletions src/Utilities/RecoilAtoms.res
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ let userPixKey = Recoil.atom("userPixKey", defaultFieldValues)
let userPixCPF = Recoil.atom("userPixCPF", defaultFieldValues)
let userPixCNPJ = Recoil.atom("userPixCNPJ", defaultFieldValues)
let isCompleteCallbackUsed = Recoil.atom("isCompleteCallbackUsed", false)
let isPaymentButtonHandlerProvidedAtom = Recoil.atom("isPaymentButtonHandlerProvidedAtom", false)

type areOneClickWalletsRendered = {
isGooglePay: bool,
Expand Down
16 changes: 8 additions & 8 deletions src/Utilities/Utils.res
Original file line number Diff line number Diff line change
Expand Up @@ -1212,25 +1212,25 @@ let getThemePromise = dict => {
}
}

let makeOneClickHandlerPromise = sdkHandleOneClickConfirmPayment => {
open EventListenerManager
let makeOneClickHandlerPromise = sdkHandleIsThere => {
Promise.make((resolve, _) => {
if sdkHandleOneClickConfirmPayment {
if !sdkHandleIsThere {
resolve(JSON.Encode.bool(true))
} else {
let handleMessage = (event: Types.event) => {
let handleMessage = (event: Window.event) => {
let json = try {
event.data->anyTypeToJson
event.data->safeParse
} catch {
| _ => JSON.Encode.null
}

let dict = json->getDictFromJson
if dict->Dict.get("oneClickDoSubmit")->Option.isSome {
resolve(dict->Dict.get("oneClickDoSubmit")->Option.getOr(true->JSON.Encode.bool))

if dict->Dict.get("walletClickEvent")->Option.isSome {
resolve(dict->Dict.get("walletClickEvent")->Option.getOr(true->JSON.Encode.bool))
}
}
addSmartEventListener("message", handleMessage, "onOneClickHandlerPaymentConfirm")
Window.addEventListener("message", handleMessage)
handleOnConfirmPostMessage(~targetOrigin="*", ~isOneClick=true)
}
})
Expand Down
61 changes: 32 additions & 29 deletions src/orca-loader/Elements.res
Original file line number Diff line number Diff line change
Expand Up @@ -296,35 +296,38 @@ let make = (
("loader", loader),
("fonts", fonts),
]->getJsonFromArrayOfJson
let message =
[
(
"paymentElementCreate",
componentType->getIsComponentTypeForPaymentElementCreate->JSON.Encode.bool,
),
("otherElements", otherElements->JSON.Encode.bool),
("options", newOptions),
("componentType", componentType->JSON.Encode.string),
("paymentOptions", widgetOptions),
("iframeId", selectorString->JSON.Encode.string),
("publishableKey", publishableKey->JSON.Encode.string),
("endpoint", endpoint->JSON.Encode.string),
("sdkSessionId", sdkSessionId->JSON.Encode.string),
("blockConfirm", blockConfirm->JSON.Encode.bool),
("customPodUri", customPodUri->JSON.Encode.string),
("sdkHandleOneClickConfirmPayment", sdkHandleOneClickConfirmPayment->JSON.Encode.bool),
("parentURL", "*"->JSON.Encode.string),
("analyticsMetadata", analyticsMetadata),
("launchTime", launchTime->JSON.Encode.float),
("customBackendUrl", customBackendUrl->JSON.Encode.string),
(
"onCompleteDoThisUsed",
EventListenerManager.eventListenerMap
->Dict.get("onCompleteDoThis")
->Option.isSome
->JSON.Encode.bool,
),
]->Dict.fromArray
let message = [
(
"paymentElementCreate",
componentType->getIsComponentTypeForPaymentElementCreate->JSON.Encode.bool,
),
("otherElements", otherElements->JSON.Encode.bool),
("options", newOptions),
("componentType", componentType->JSON.Encode.string),
("paymentOptions", widgetOptions),
("iframeId", selectorString->JSON.Encode.string),
("publishableKey", publishableKey->JSON.Encode.string),
("endpoint", endpoint->JSON.Encode.string),
("sdkSessionId", sdkSessionId->JSON.Encode.string),
("blockConfirm", blockConfirm->JSON.Encode.bool),
("customPodUri", customPodUri->JSON.Encode.string),
("sdkHandleOneClickConfirmPayment", sdkHandleOneClickConfirmPayment->JSON.Encode.bool),
("parentURL", "*"->JSON.Encode.string),
("analyticsMetadata", analyticsMetadata),
("launchTime", launchTime->JSON.Encode.float),
("customBackendUrl", customBackendUrl->JSON.Encode.string),
(
"isPaymentButtonHandlerProvided",
LoaderPaymentElement.isPaymentButtonHandlerProvided.contents->JSON.Encode.bool,
),
(
"onCompleteDoThisUsed",
EventListenerManager.eventListenerMap
->Dict.get("onCompleteDoThis")
->Option.isSome
->JSON.Encode.bool,
),
]->Dict.fromArray

let wallets = PaymentType.getWallets(newOptions->getDictFromJson, "wallets", logger)

Expand Down
45 changes: 45 additions & 0 deletions src/orca-loader/LoaderPaymentElement.res
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ open Identity
@val @scope(("navigator", "clipboard"))
external writeText: string => promise<'a> = "writeText"

let onCompleteDoThisUsed = ref(false)
let isPaymentButtonHandlerProvided = ref(false)
let make = (
componentType,
options,
Expand All @@ -32,6 +34,48 @@ let make = (
true,
)

let asyncWrapper = async fn => {
try {
await fn()
} catch {
| err => Console.log2("Async function call failure", err)
}
}

let currEventHandler = ref(Some(() => Promise.make((_, _) => {()})))
let walletOneClickEventHandler = (event: Types.event) => {
let json = try {
event.data->anyTypeToJson
} catch {
| _ => JSON.Encode.null
}

let dict = json->getDictFromJson
if dict->Dict.get("oneClickConfirmTriggered")->Option.isSome {
switch currEventHandler.contents {
| Some(eH) =>
asyncWrapper(eH)
->Promise.then(() => {
let msg = [("walletClickEvent", true->JSON.Encode.bool)]->Dict.fromArray
event.source->Window.sendPostMessage(msg)
Promise.resolve()
})
->ignore

| None => ()
}
}
}

Window.addEventListener("message", walletOneClickEventHandler)

let onSDKHandleClick = (eventHandler: option<unit => RescriptCore.Promise.t<'a>>) => {
currEventHandler := eventHandler
if eventHandler->Option.isSome {
isPaymentButtonHandlerProvided := true
}
}

let on = (eventType, eventHandler) => {
switch eventType->eventTypeMapper {
| Escape =>
Expand Down Expand Up @@ -368,6 +412,7 @@ let make = (
destroy,
update,
mount,
onSDKHandleClick,
}
} catch {
| e => {
Expand Down
4 changes: 4 additions & 0 deletions src/orca-loader/Types.res
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type paymentElement = {
mount: string => unit,
focus: unit => unit,
clear: unit => unit,
onSDKHandleClick: option<unit => Promise.t<unit>> => unit,
}

type element = {
Expand Down Expand Up @@ -107,6 +108,8 @@ let fetchUpdates = () => {
setTimeout(() => resolve(Dict.make()->JSON.Encode.object), 1000)->ignore
})
}

let fnArgument = Some(() => Promise.make((_, _) => {()}))
let defaultPaymentElement = {
on: (_str, _func) => (),
collapse: () => (),
Expand All @@ -117,6 +120,7 @@ let defaultPaymentElement = {
mount: _string => (),
focus: () => (),
clear: () => (),
onSDKHandleClick: fnArgument => (),
}

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

0 comments on commit 9c09ff2

Please sign in to comment.