From 4f65ecbeb48022dbe9da507d98344e43c308b691 Mon Sep 17 00:00:00 2001 From: sakksham7 <130480324+sakksham7@users.noreply.github.com> Date: Tue, 15 Oct 2024 16:52:07 +0530 Subject: [PATCH 1/8] feat: added confirm handler (#731) --- src/LoaderController.res | 7 ++++++ src/Payments/PaypalSDK.res | 2 ++ src/Payments/PaypalSDKHelpers.res | 1 + src/Utilities/PaymentHelpers.res | 28 +++++++++++++++++++++--- src/Utilities/RecoilAtoms.res | 1 + src/Utilities/Utils.res | 5 +++++ src/orca-loader/Elements.res | 7 ++++++ src/orca-loader/LoaderPaymentElement.res | 7 ++++++ src/orca-loader/Types.res | 13 ++++++++++- 9 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/LoaderController.res b/src/LoaderController.res index d81b6457b..31fa6e4a6 100644 --- a/src/LoaderController.res +++ b/src/LoaderController.res @@ -35,6 +35,9 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime let setUserAddressState = Recoil.useLoggedSetRecoilState(userAddressState, "state", logger) let setUserAddressCountry = Recoil.useLoggedSetRecoilState(userAddressCountry, "country", logger) let (_country, setCountry) = Recoil.useRecoilState(userCountry) + let (isCompleteCallbackUsed, setIsCompleteCallbackUsed) = Recoil.useRecoilState( + isCompleteCallbackUsed, + ) let optionsCallback = (optionsPayment: PaymentType.options) => { [ @@ -245,6 +248,10 @@ 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("paymentOptions") { let paymentOptions = dict->getDictFromObj("paymentOptions") diff --git a/src/Payments/PaypalSDK.res b/src/Payments/PaypalSDK.res index 7763a6fd7..f92957c67 100644 --- a/src/Payments/PaypalSDK.res +++ b/src/Payments/PaypalSDK.res @@ -9,6 +9,7 @@ let make = (~sessionObj: SessionsType.token, ~paymentType: CardThemeType.mode) = let areOneClickWalletsRendered = Recoil.useSetRecoilState(RecoilAtoms.areOneClickWalletsRendered) let paymentMethodListValue = Recoil.useRecoilValueFromAtom(PaymentUtils.paymentMethodListValue) let (isCompleted, setIsCompleted) = React.useState(_ => false) + let isCallbackUsedVal = Recoil.useRecoilValueFromAtom(RecoilAtoms.isCompleteCallbackUsed) let token = sessionObj.token let orderDetails = sessionObj.orderDetails->getOrderDetails(paymentType) @@ -90,6 +91,7 @@ let make = (~sessionObj: SessionsType.token, ~paymentType: CardThemeType.mode) = ~handleCloseLoader, ~areOneClickWalletsRendered, ~setIsCompleted, + ~isCallbackUsedVal, ) }) Window.body->Window.appendChild(paypalScript) diff --git a/src/Payments/PaypalSDKHelpers.res b/src/Payments/PaypalSDKHelpers.res index 71c08e1e5..c9287ff57 100644 --- a/src/Payments/PaypalSDKHelpers.res +++ b/src/Payments/PaypalSDKHelpers.res @@ -20,6 +20,7 @@ let loadPaypalSDK = ( RecoilAtoms.areOneClickWalletsRendered => RecoilAtoms.areOneClickWalletsRendered ) => unit, ~setIsCompleted, + ~isCallbackUsedVal: bool, ) => { loggerState.setLogInfo( ~value="Paypal SDK Button Clicked", diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index af404ea10..981517c51 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -315,9 +315,11 @@ let rec intentCall = ( ~sdkHandleOneClickConfirmPayment, ~counter, ~isPaymentSession=false, + ~isCallbackUsedVal=?, ) => { open Promise let isConfirm = uri->String.includes("/confirm") + let isCompleteAuthorize = uri->String.includes("/complete_authorize") let (eventName: OrcaLogger.eventName, initEventName: OrcaLogger.eventName) = switch ( isConfirm, @@ -506,14 +508,28 @@ let rec intentCall = ( | (Applepay, false) | (Paypal, false) => if !isPaymentSession { - closePaymentLoaderIfAny() + if isCallbackUsedVal->Option.getOr(false) { + Utils.handleOnCompleteDoThisMessage() + } else { + closePaymentLoaderIfAny() + } + postSubmitResponse(~jsonData=data, ~url=url.href) } else if confirmParam.redirect === Some("always") { - handleOpenUrl(url.href) + if isCallbackUsedVal->Option.getOr(false) { + Utils.handleOnCompleteDoThisMessage() + } else { + handleOpenUrl(url.href) + } } else { resolve(data) } - | _ => handleOpenUrl(url.href) + | _ => + if isCallbackUsedVal->Option.getOr(false) { + Utils.handleOnCompleteDoThisMessage() + } else { + handleOpenUrl(url.href) + } } } @@ -890,6 +906,7 @@ let usePaymentSync = (optLogger: option, paymentType: pay open RecoilAtoms let paymentMethodList = Recoil.useRecoilValueFromAtom(paymentMethodList) let keys = Recoil.useRecoilValueFromAtom(keys) + let isCallbackUsedVal = Recoil.useRecoilValueFromAtom(RecoilAtoms.isCompleteCallbackUsed) let customPodUri = Recoil.useRecoilValueFromAtom(customPodUri) let setIsManualRetryEnabled = Recoil.useSetRecoilState(isManualRetryEnabled) (~handleUserError=false, ~confirmParam: ConfirmType.confirmParams, ~iframeId="") => { @@ -917,6 +934,7 @@ let usePaymentSync = (optLogger: option, paymentType: pay ~customPodUri, ~sdkHandleOneClickConfirmPayment=keys.sdkHandleOneClickConfirmPayment, ~counter=0, + ~isCallbackUsedVal, )->ignore } switch paymentMethodList { @@ -963,6 +981,7 @@ let usePaymentIntent = (optLogger, paymentType) => { let customPodUri = Recoil.useRecoilValueFromAtom(customPodUri) let paymentMethodList = Recoil.useRecoilValueFromAtom(paymentMethodList) let keys = Recoil.useRecoilValueFromAtom(keys) + let isCallbackUsedVal = Recoil.useRecoilValueFromAtom(RecoilAtoms.isCompleteCallbackUsed) let setIsManualRetryEnabled = Recoil.useSetRecoilState(isManualRetryEnabled) ( @@ -1056,6 +1075,7 @@ let usePaymentIntent = (optLogger, paymentType) => { ~customPodUri, ~sdkHandleOneClickConfirmPayment=keys.sdkHandleOneClickConfirmPayment, ~counter=0, + ~isCallbackUsedVal, ) ->then(val => { intentCallback(val) @@ -1140,6 +1160,7 @@ let useCompleteAuthorize = (optLogger: option, paymentTyp let customPodUri = Recoil.useRecoilValueFromAtom(customPodUri) let setIsManualRetryEnabled = Recoil.useSetRecoilState(isManualRetryEnabled) let url = RescriptReactRouter.useUrl() + let isCallbackUsedVal = Recoil.useRecoilValueFromAtom(RecoilAtoms.isCompleteCallbackUsed) let paymentTypeFromUrl = CardUtils.getQueryParamsDictforKey(url.search, "componentName")->CardThemeType.getPaymentMode ( @@ -1183,6 +1204,7 @@ let useCompleteAuthorize = (optLogger: option, paymentTyp ~customPodUri, ~sdkHandleOneClickConfirmPayment=keys.sdkHandleOneClickConfirmPayment, ~counter=0, + ~isCallbackUsedVal, )->ignore } switch paymentMethodList { diff --git a/src/Utilities/RecoilAtoms.res b/src/Utilities/RecoilAtoms.res index 26752e0f4..6c2da891b 100644 --- a/src/Utilities/RecoilAtoms.res +++ b/src/Utilities/RecoilAtoms.res @@ -73,6 +73,7 @@ let userVpaId = Recoil.atom("userVpaId", defaultFieldValues) let userPixKey = Recoil.atom("userPixKey", defaultFieldValues) let userPixCPF = Recoil.atom("userPixCPF", defaultFieldValues) let userPixCNPJ = Recoil.atom("userPixCNPJ", defaultFieldValues) +let isCompleteCallbackUsed = Recoil.atom("isCompleteCallbackUsed", false) type areOneClickWalletsRendered = { isGooglePay: bool, diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res index a571fd0fb..5c35b3524 100644 --- a/src/Utilities/Utils.res +++ b/src/Utilities/Utils.res @@ -28,6 +28,10 @@ let handleOnFocusPostMessage = (~targetOrigin="*") => { messageParentWindow([("focus", true->JSON.Encode.bool)], ~targetOrigin) } +let handleOnCompleteDoThisMessage = (~targetOrigin="*") => { + messageParentWindow([("completeDoThis", true->JSON.Encode.bool)], ~targetOrigin) +} + let handleOnBlurPostMessage = (~targetOrigin="*") => { messageParentWindow([("blur", true->JSON.Encode.bool)], ~targetOrigin) } @@ -1148,6 +1152,7 @@ let eventHandlerFunc = ( | Click | Ready | Focus + | CompleteDoThis | ConfirmPayment | OneClickConfirmPayment | Blur => diff --git a/src/orca-loader/Elements.res b/src/orca-loader/Elements.res index a493e6ed7..58828faf2 100644 --- a/src/orca-loader/Elements.res +++ b/src/orca-loader/Elements.res @@ -317,6 +317,13 @@ let make = ( ("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 wallets = PaymentType.getWallets(newOptions->getDictFromJson, "wallets", logger) diff --git a/src/orca-loader/LoaderPaymentElement.res b/src/orca-loader/LoaderPaymentElement.res index 028e50132..a80176a48 100644 --- a/src/orca-loader/LoaderPaymentElement.res +++ b/src/orca-loader/LoaderPaymentElement.res @@ -47,6 +47,13 @@ let make = ( }, "onEscape", ) + | CompleteDoThis => + eventHandlerFunc( + ev => ev.data.completeDoThis, + eventHandler, + CompleteDoThis, + "onCompleteDoThis", + ) | Change => eventHandlerFunc( ev => ev.data.elementType === componentType, diff --git a/src/orca-loader/Types.res b/src/orca-loader/Types.res index 5186769da..74e8eb07e 100644 --- a/src/orca-loader/Types.res +++ b/src/orca-loader/Types.res @@ -4,6 +4,7 @@ type eventData = { blur: bool, ready: bool, clickTriggered: bool, + completeDoThis: bool, elementType: string, classChange: bool, newClassType: string, @@ -184,7 +185,16 @@ let defaultHyperInstance = { } type eventType = - Escape | Change | Click | Ready | Focus | Blur | ConfirmPayment | OneClickConfirmPayment | None + | Escape + | Change + | Click + | Ready + | Focus + | Blur + | CompleteDoThis + | ConfirmPayment + | OneClickConfirmPayment + | None let eventTypeMapper = event => { switch event { @@ -192,6 +202,7 @@ let eventTypeMapper = event => { | "change" => Change | "clickTriggered" => Click | "ready" => Ready + | "completeDoThis" => CompleteDoThis | "focus" => Focus | "blur" => Blur | "confirmTriggered" => ConfirmPayment From 5c08f6689a8a8277f7da20f329d5a7d5d8d783a3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 15 Oct 2024 11:24:09 +0000 Subject: [PATCH 2/8] chore(release): 0.93.0 [skip ci] # [0.93.0](https://github.com/juspay/hyperswitch-web/compare/v0.92.1...v0.93.0) (2024-10-15) ### Features * added confirm handler ([#731](https://github.com/juspay/hyperswitch-web/issues/731)) ([4f65ecb](https://github.com/juspay/hyperswitch-web/commit/4f65ecbeb48022dbe9da507d98344e43c308b691)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 627e0d630..bae625bf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.93.0](https://github.com/juspay/hyperswitch-web/compare/v0.92.1...v0.93.0) (2024-10-15) + + +### Features + +* added confirm handler ([#731](https://github.com/juspay/hyperswitch-web/issues/731)) ([4f65ecb](https://github.com/juspay/hyperswitch-web/commit/4f65ecbeb48022dbe9da507d98344e43c308b691)) + ## [0.92.1](https://github.com/juspay/hyperswitch-web/compare/v0.92.0...v0.92.1) (2024-10-10) diff --git a/package-lock.json b/package-lock.json index 2d1564c42..9ce2d5343 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.92.1", + "version": "0.93.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.92.1", + "version": "0.93.0", "hasInstallScript": true, "dependencies": { "@glennsl/rescript-fetch": "^0.2.0", diff --git a/package.json b/package.json index 7780a714e..6c4849a45 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.92.1", + "version": "0.93.0", "main": "index.js", "private": true, "dependencies": { From 9c09ff2d90ece78583c897c9cb29f2f45f346f90 Mon Sep 17 00:00:00 2001 From: sakksham7 <130480324+sakksham7@users.noreply.github.com> Date: Tue, 15 Oct 2024 18:52:49 +0530 Subject: [PATCH 3/8] feat: added click handler (#732) --- CHANGELOG.md | 2 +- src/LoaderController.res | 8 ++++ src/Payments/ApplePay.res | 13 +++-- src/Payments/GPay.res | 5 +- src/Payments/KlarnaSDK.res | 11 +++-- src/Payments/PayPal.res | 5 +- src/Payments/PaypalSDK.res | 4 ++ src/Payments/PaypalSDKHelpers.res | 3 +- src/Utilities/RecoilAtoms.res | 1 + src/Utilities/Utils.res | 16 +++---- src/orca-loader/Elements.res | 61 +++++++++++++----------- src/orca-loader/LoaderPaymentElement.res | 45 +++++++++++++++++ src/orca-loader/Types.res | 4 ++ 13 files changed, 126 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bae625bf4..3e913f58a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) \ No newline at end of file diff --git a/src/LoaderController.res b/src/LoaderController.res index 31fa6e4a6..838cedee2 100644 --- a/src/LoaderController.res +++ b/src/LoaderController.res @@ -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) => { [ @@ -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") diff --git a/src/Payments/ApplePay.res b/src/Payments/ApplePay.res index afbc951e0..0152259eb 100644 --- a/src/Payments/ApplePay.res +++ b/src/Payments/ApplePay.res @@ -5,9 +5,10 @@ let make = (~sessionObj: option, ~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) @@ -212,7 +213,7 @@ let make = (~sessionObj: option, ~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 { @@ -241,7 +242,11 @@ let make = (~sessionObj: option, ~walletOptions, ~paymentType: CardTheme ~isManualRetryEnabled, ) } else { - ApplePayHelpers.handleApplePayButtonClicked(~sessionObj, ~componentName, ~paymentMethodListValue) + ApplePayHelpers.handleApplePayButtonClicked( + ~sessionObj, + ~componentName, + ~paymentMethodListValue, + ) } } else { let bodyDict = PaymentBody.applePayRedirectBody(~connectors) diff --git a/src/Payments/GPay.res b/src/Payments/GPay.res index 92e008ec9..d9e0c69d1 100644 --- a/src/Payments/GPay.res +++ b/src/Payments/GPay.res @@ -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) @@ -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 { diff --git a/src/Payments/KlarnaSDK.res b/src/Payments/KlarnaSDK.res index b5b80397d..a53771a7b 100644 --- a/src/Payments/KlarnaSDK.res +++ b/src/Payments/KlarnaSDK.res @@ -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 @@ -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 { diff --git a/src/Payments/PayPal.res b/src/Payments/PayPal.res index acc65239b..f7edbb5ff 100644 --- a/src/Payments/PayPal.res +++ b/src/Payments/PayPal.res @@ -14,7 +14,8 @@ let payPalIcon = 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) @@ -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 { diff --git a/src/Payments/PaypalSDK.res b/src/Payments/PaypalSDK.res index f92957c67..1abbc2886 100644 --- a/src/Payments/PaypalSDK.res +++ b/src/Payments/PaypalSDK.res @@ -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) @@ -92,6 +95,7 @@ let make = (~sessionObj: SessionsType.token, ~paymentType: CardThemeType.mode) = ~areOneClickWalletsRendered, ~setIsCompleted, ~isCallbackUsedVal, + ~sdkHandleIsThere, ) }) Window.body->Window.appendChild(paypalScript) diff --git a/src/Payments/PaypalSDKHelpers.res b/src/Payments/PaypalSDKHelpers.res index c9287ff57..e05a477b7 100644 --- a/src/Payments/PaypalSDKHelpers.res +++ b/src/Payments/PaypalSDKHelpers.res @@ -21,6 +21,7 @@ let loadPaypalSDK = ( ) => unit, ~setIsCompleted, ~isCallbackUsedVal: bool, + ~sdkHandleIsThere: bool, ) => { loggerState.setLogInfo( ~value="Paypal SDK Button Clicked", @@ -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([ diff --git a/src/Utilities/RecoilAtoms.res b/src/Utilities/RecoilAtoms.res index 6c2da891b..d1207655f 100644 --- a/src/Utilities/RecoilAtoms.res +++ b/src/Utilities/RecoilAtoms.res @@ -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, diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res index 5c35b3524..5a3b518f9 100644 --- a/src/Utilities/Utils.res +++ b/src/Utilities/Utils.res @@ -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) } }) diff --git a/src/orca-loader/Elements.res b/src/orca-loader/Elements.res index 58828faf2..110353b7c 100644 --- a/src/orca-loader/Elements.res +++ b/src/orca-loader/Elements.res @@ -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) diff --git a/src/orca-loader/LoaderPaymentElement.res b/src/orca-loader/LoaderPaymentElement.res index a80176a48..a09d0e8d8 100644 --- a/src/orca-loader/LoaderPaymentElement.res +++ b/src/orca-loader/LoaderPaymentElement.res @@ -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, @@ -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 RescriptCore.Promise.t<'a>>) => { + currEventHandler := eventHandler + if eventHandler->Option.isSome { + isPaymentButtonHandlerProvided := true + } + } + let on = (eventType, eventHandler) => { switch eventType->eventTypeMapper { | Escape => @@ -368,6 +412,7 @@ let make = ( destroy, update, mount, + onSDKHandleClick, } } catch { | e => { diff --git a/src/orca-loader/Types.res b/src/orca-loader/Types.res index 74e8eb07e..932612800 100644 --- a/src/orca-loader/Types.res +++ b/src/orca-loader/Types.res @@ -31,6 +31,7 @@ type paymentElement = { mount: string => unit, focus: unit => unit, clear: unit => unit, + onSDKHandleClick: option Promise.t> => unit, } type element = { @@ -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: () => (), @@ -117,6 +120,7 @@ let defaultPaymentElement = { mount: _string => (), focus: () => (), clear: () => (), + onSDKHandleClick: fnArgument => (), } let create = (_componentType, _options) => { From f1f8d3287fb523e1214688a5e81314811dd14eda Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 15 Oct 2024 13:24:57 +0000 Subject: [PATCH 4/8] chore(release): 0.94.0 [skip ci] # [0.94.0](https://github.com/juspay/hyperswitch-web/compare/v0.93.0...v0.94.0) (2024-10-15) ### Features * added click handler ([#732](https://github.com/juspay/hyperswitch-web/issues/732)) ([9c09ff2](https://github.com/juspay/hyperswitch-web/commit/9c09ff2d90ece78583c897c9cb29f2f45f346f90)) --- CHANGELOG.md | 9 ++++++++- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e913f58a..f54bbf42e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.94.0](https://github.com/juspay/hyperswitch-web/compare/v0.93.0...v0.94.0) (2024-10-15) + + +### Features + +* added click handler ([#732](https://github.com/juspay/hyperswitch-web/issues/732)) ([9c09ff2](https://github.com/juspay/hyperswitch-web/commit/9c09ff2d90ece78583c897c9cb29f2f45f346f90)) + # [0.93.0](https://github.com/juspay/hyperswitch-web/compare/v0.92.1...v0.93.0) (2024-10-15) @@ -2370,4 +2377,4 @@ ### Features -* updated Readme ([427f8fd](https://github.com/juspay/hyperswitch-web/commit/427f8fd91be58fc63b0fa4ab326d562a4caaabab)) \ No newline at end of file +* updated Readme ([427f8fd](https://github.com/juspay/hyperswitch-web/commit/427f8fd91be58fc63b0fa4ab326d562a4caaabab)) diff --git a/package-lock.json b/package-lock.json index 9ce2d5343..3d4424941 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.93.0", + "version": "0.94.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.93.0", + "version": "0.94.0", "hasInstallScript": true, "dependencies": { "@glennsl/rescript-fetch": "^0.2.0", diff --git a/package.json b/package.json index 6c4849a45..7bdfebcc0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.93.0", + "version": "0.94.0", "main": "index.js", "private": true, "dependencies": { From 5b7e78b49fe4ce7e05fafb4e259dfa6a3f71919e Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja Date: Tue, 15 Oct 2024 19:00:37 +0530 Subject: [PATCH 5/8] fix: callback fix --- src/orca-loader/LoaderPaymentElement.res | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/orca-loader/LoaderPaymentElement.res b/src/orca-loader/LoaderPaymentElement.res index a09d0e8d8..add7383b7 100644 --- a/src/orca-loader/LoaderPaymentElement.res +++ b/src/orca-loader/LoaderPaymentElement.res @@ -92,12 +92,14 @@ let make = ( "onEscape", ) | CompleteDoThis => - eventHandlerFunc( - ev => ev.data.completeDoThis, - eventHandler, - CompleteDoThis, - "onCompleteDoThis", - ) + if eventHandler->Option.isSome { + eventHandlerFunc( + ev => ev.data.completeDoThis, + eventHandler, + CompleteDoThis, + "onCompleteDoThis", + ) + } | Change => eventHandlerFunc( ev => ev.data.elementType === componentType, From ba47f2f662c962a3ff7c4a8aa664939bfcadd6ab Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 15 Oct 2024 13:32:57 +0000 Subject: [PATCH 6/8] chore(release): 0.94.1 [skip ci] ## [0.94.1](https://github.com/juspay/hyperswitch-web/compare/v0.94.0...v0.94.1) (2024-10-15) ### Bug Fixes * callback fix ([5b7e78b](https://github.com/juspay/hyperswitch-web/commit/5b7e78b49fe4ce7e05fafb4e259dfa6a3f71919e)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f54bbf42e..87f958649 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.94.1](https://github.com/juspay/hyperswitch-web/compare/v0.94.0...v0.94.1) (2024-10-15) + + +### Bug Fixes + +* callback fix ([5b7e78b](https://github.com/juspay/hyperswitch-web/commit/5b7e78b49fe4ce7e05fafb4e259dfa6a3f71919e)) + # [0.94.0](https://github.com/juspay/hyperswitch-web/compare/v0.93.0...v0.94.0) (2024-10-15) diff --git a/package-lock.json b/package-lock.json index 3d4424941..4e5fc3453 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.94.0", + "version": "0.94.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.94.0", + "version": "0.94.1", "hasInstallScript": true, "dependencies": { "@glennsl/rescript-fetch": "^0.2.0", diff --git a/package.json b/package.json index 7bdfebcc0..ddf8ff3eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.94.0", + "version": "0.94.1", "main": "index.js", "private": true, "dependencies": { From 07c96127d60c0f598cb1ae6aadd95c9ce887d350 Mon Sep 17 00:00:00 2001 From: Sagnik Mitra <83326850+ImSagnik007@users.noreply.github.com> Date: Tue, 15 Oct 2024 20:38:16 +0530 Subject: [PATCH 7/8] refactor: Paypal Flow Refactor (#736) Co-authored-by: Pritish Budhiraja --- src/Components/SavedPaymentManagement.res | 2 +- src/Payments/PaypalSDK.res | 10 +- src/Payments/PaypalSDKHelpers.res | 111 +++++++++--- src/Utilities/PaymentHelpers.res | 198 +++++++++++++++++++++- src/Utilities/PaymentUtils.res | 2 +- src/orca-log-catcher/OrcaLogger.res | 4 + 6 files changed, 296 insertions(+), 31 deletions(-) diff --git a/src/Components/SavedPaymentManagement.res b/src/Components/SavedPaymentManagement.res index f492b4b24..f213bef33 100644 --- a/src/Components/SavedPaymentManagement.res +++ b/src/Components/SavedPaymentManagement.res @@ -9,7 +9,7 @@ let make = (~savedMethods: array, ~setSavedMethods) let logger = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom) let removeSavedMethod = ( - savedMethods: array, + savedMethods: array, paymentMethodId, ) => { savedMethods->Array.filter(savedMethod => { diff --git a/src/Payments/PaypalSDK.res b/src/Payments/PaypalSDK.res index 1abbc2886..952c304b9 100644 --- a/src/Payments/PaypalSDK.res +++ b/src/Payments/PaypalSDK.res @@ -16,9 +16,11 @@ let make = (~sessionObj: SessionsType.token, ~paymentType: CardThemeType.mode) = let token = sessionObj.token let orderDetails = sessionObj.orderDetails->getOrderDetails(paymentType) - let intent = PaymentHelpers.usePaymentIntent(Some(loggerState), Paypal) - let isManualRetryEnabled = Recoil.useRecoilValueFromAtom(RecoilAtoms.isManualRetryEnabled) + let intent = PaymentHelpers.usePostSessionTokens(Some(loggerState), Paypal, Wallet) + let confirm = PaymentHelpers.usePaymentIntent(Some(loggerState), Paypal) + let sessions = Recoil.useRecoilValueFromAtom(RecoilAtoms.sessions) let completeAuthorize = PaymentHelpers.useCompleteAuthorize(Some(loggerState), Paypal) + let isManualRetryEnabled = Recoil.useRecoilValueFromAtom(RecoilAtoms.isManualRetryEnabled) let checkoutScript = Window.document(Window.window)->Window.getElementById("braintree-checkout")->Nullable.toOption let clientScript = @@ -84,18 +86,20 @@ let make = (~sessionObj: SessionsType.token, ~paymentType: CardThemeType.mode) = ~iframeId, ~paymentMethodListValue, ~isGuestCustomer, - ~intent, + ~postSessionTokens=intent, ~isManualRetryEnabled, ~options, ~publishableKey, ~paymentMethodTypes, ~stateJson, + ~confirm, ~completeAuthorize, ~handleCloseLoader, ~areOneClickWalletsRendered, ~setIsCompleted, ~isCallbackUsedVal, ~sdkHandleIsThere, + ~sessions, ) }) Window.body->Window.appendChild(paypalScript) diff --git a/src/Payments/PaypalSDKHelpers.res b/src/Payments/PaypalSDKHelpers.res index e05a477b7..0b4bc071b 100644 --- a/src/Payments/PaypalSDKHelpers.res +++ b/src/Payments/PaypalSDKHelpers.res @@ -1,27 +1,30 @@ open PaypalSDKTypes open Promise +open Utils let loadPaypalSDK = ( ~loggerState: OrcaLogger.loggerMake, - ~sdkHandleOneClickConfirmPayment, + ~sdkHandleOneClickConfirmPayment as _, ~buttonStyle, ~iframeId, ~isManualRetryEnabled, ~paymentMethodListValue, ~isGuestCustomer, - ~intent: PaymentHelpers.paymentIntent, + ~postSessionTokens: PaymentHelpers.paymentIntent, ~options: PaymentType.options, ~publishableKey, ~paymentMethodTypes, ~stateJson, + ~confirm: PaymentHelpers.paymentIntent, ~completeAuthorize: PaymentHelpers.completeAuthorize, ~handleCloseLoader, ~areOneClickWalletsRendered: ( RecoilAtoms.areOneClickWalletsRendered => RecoilAtoms.areOneClickWalletsRendered ) => unit, ~setIsCompleted, - ~isCallbackUsedVal: bool, + ~isCallbackUsedVal as _: bool, ~sdkHandleIsThere: bool, + ~sessions: PaymentType.loadType, ) => { loggerState.setLogInfo( ~value="Paypal SDK Button Clicked", @@ -31,6 +34,23 @@ let loadPaypalSDK = ( let paypalWrapper = GooglePayType.getElementById(Utils.document, "paypal-button") paypalWrapper.innerHTML = "" setIsCompleted(_ => true) + let paypalNextAction = switch sessions { + | Loaded(data) => + data + ->getDictFromJson + ->getOptionalArrayFromDict("session_token") + ->Option.flatMap(arr => { + arr->Array.find(ele => ele->getDictFromJson->getString("connector", "") == "paypal") + }) + ->Option.flatMap(ele => { + ele + ->getDictFromJson + ->getDictFromDict("sdk_next_action") + ->getOptionString("next_action") + }) + ->Option.getOr("") + | _ => "" + } paypal["Buttons"]({ style: buttonStyle, fundingSource: paypal["FUNDING"]["PAYPAL"], @@ -52,17 +72,36 @@ let loadPaypalSDK = ( ~body, ) Promise.make((resolve, _) => { - intent( - ~bodyArr=modifiedPaymentBody, - ~confirmParam={ - return_url: options.wallets.walletReturnUrl, - publishableKey, - }, - ~handleUserError=true, - ~intentCallback=val => - val->Utils.getDictFromJson->Utils.getString("orderId", "")->resolve, - ~manualRetry=isManualRetryEnabled, - ) + if paypalNextAction == "post_session_tokens" { + postSessionTokens( + ~bodyArr=modifiedPaymentBody, + ~confirmParam={ + return_url: options.wallets.walletReturnUrl, + publishableKey, + }, + ~handleUserError=true, + ~intentCallback=val => { + val + ->Utils.getDictFromJson + ->Utils.getDictFromDict("nextActionData") + ->Utils.getString("order_id", "") + ->resolve + }, + ~manualRetry=isManualRetryEnabled, + ) + } else { + confirm( + ~bodyArr=modifiedPaymentBody, + ~confirmParam={ + return_url: options.wallets.walletReturnUrl, + publishableKey, + }, + ~handleUserError=true, + ~intentCallback=val => + val->Utils.getDictFromJson->Utils.getString("orderId", "")->resolve, + ~manualRetry=isManualRetryEnabled, + ) + } }) } else { loggerState.setLogInfo( @@ -100,22 +139,46 @@ let loadPaypalSDK = ( ~statesList=stateJson, ) + let (connectors, _) = + paymentMethodListValue->PaymentUtils.getConnectors(Wallets(Paypal(SDK))) + + let orderId = val->Utils.getDictFromJson->Utils.getString("id", "") + let body = PaymentBody.paypalSdkBody(~token=orderId, ~connectors) + let modifiedPaymentBody = PaymentUtils.appendedCustomerAcceptance( + ~isGuestCustomer, + ~paymentType=paymentMethodListValue.payment_type, + ~body, + ) + let bodyArr = requiredFieldsBody ->JSON.Encode.object ->Utils.unflattenObject ->Utils.getArrayOfTupleFromDict - completeAuthorize( - ~bodyArr, - ~confirmParam={ - return_url: options.wallets.walletReturnUrl, - publishableKey, - }, - ~handleUserError=true, - ) - - resolve() + let confirmBody = bodyArr->Array.concatMany([modifiedPaymentBody]) + Promise.make((_resolve, _) => { + if paypalNextAction == "post_session_tokens" { + confirm( + ~bodyArr=confirmBody, + ~confirmParam={ + return_url: options.wallets.walletReturnUrl, + publishableKey, + }, + ~handleUserError=true, + ~manualRetry=true, + ) + } else { + completeAuthorize( + ~bodyArr, + ~confirmParam={ + return_url: options.wallets.walletReturnUrl, + publishableKey, + }, + ~handleUserError=true, + ) + } + }) }) ->ignore } diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index 981517c51..0fa7d7b5e 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -321,12 +321,15 @@ let rec intentCall = ( let isConfirm = uri->String.includes("/confirm") let isCompleteAuthorize = uri->String.includes("/complete_authorize") + let isPostSessionTokens = uri->String.includes("/post_session_tokens") let (eventName: OrcaLogger.eventName, initEventName: OrcaLogger.eventName) = switch ( isConfirm, isCompleteAuthorize, + isPostSessionTokens, ) { - | (true, _) => (CONFIRM_CALL, CONFIRM_CALL_INIT) - | (_, true) => (COMPLETE_AUTHORIZE_CALL, COMPLETE_AUTHORIZE_CALL_INIT) + | (true, _, _) => (CONFIRM_CALL, CONFIRM_CALL_INIT) + | (_, true, _) => (COMPLETE_AUTHORIZE_CALL, COMPLETE_AUTHORIZE_CALL_INIT) + | (_, _, true) => (POST_SESSION_TOKENS_CALL, POST_SESSION_TOKENS_CALL_INIT) | _ => (RETRIEVE_CALL, RETRIEVE_CALL_INIT) } logApi( @@ -763,6 +766,17 @@ let rec intentCall = ( resolve(failedSubmitResponse) } } + } else if intent.status == "requires_payment_method" { + if intent.nextAction.type_ === "invoke_sdk_client" { + let nextActionData = + intent.nextAction.next_action_data->Option.getOr(JSON.Encode.null) + let response = + [ + ("orderId", intent.connectorTransactionId->JSON.Encode.string), + ("nextActionData", nextActionData), + ]->getJsonFromArrayOfJson + resolve(response) + } } else if intent.status == "processing" { if intent.nextAction.type_ == "third_party_sdk_session_token" { let session_token = switch intent.nextAction.session_token { @@ -2072,3 +2086,183 @@ let calculateTax = ( JSON.Encode.null->resolve }) } + +let usePostSessionTokens = ( + optLogger, + paymentType: payment, + paymentMethod: PaymentMethodCollectTypes.paymentMethod, +) => { + open RecoilAtoms + open Promise + let url = RescriptReactRouter.useUrl() + let paymentTypeFromUrl = + CardUtils.getQueryParamsDictforKey(url.search, "componentName")->CardThemeType.getPaymentMode + let customPodUri = Recoil.useRecoilValueFromAtom(customPodUri) + let paymentMethodList = Recoil.useRecoilValueFromAtom(paymentMethodList) + let keys = Recoil.useRecoilValueFromAtom(keys) + + let setIsManualRetryEnabled = Recoil.useSetRecoilState(isManualRetryEnabled) + ( + ~handleUserError=false, + ~bodyArr: array<(string, JSON.t)>, + ~confirmParam: ConfirmType.confirmParams, + ~iframeId=keys.iframeId, + ~isThirdPartyFlow=false, + ~intentCallback=_ => (), + ~manualRetry as _=false, + ) => { + switch keys.clientSecret { + | Some(clientSecret) => + let paymentIntentID = clientSecret->getPaymentId + let headers = [ + ("Content-Type", "application/json"), + ("api-key", confirmParam.publishableKey), + ("X-Client-Source", paymentTypeFromUrl->CardThemeType.getPaymentModeToStrMapper), + ] + let body = [ + ("client_secret", clientSecret->JSON.Encode.string), + ("payment_id", paymentIntentID->JSON.Encode.string), + ("payment_method_type", (paymentType :> string)->JSON.Encode.string), + ("payment_method", (paymentMethod :> string)->JSON.Encode.string), + ] + + let endpoint = ApiEndpoint.getApiEndPoint( + ~publishableKey=confirmParam.publishableKey, + ~isConfirmCall=isThirdPartyFlow, + ) + let uri = `${endpoint}/payments/${paymentIntentID}/post_session_tokens` + + let callIntent = body => { + let contentLength = body->String.length->Int.toString + let maskedPayload = + body->safeParseOpt->Option.getOr(JSON.Encode.null)->maskPayload->JSON.stringify + let loggerPayload = + [ + ("payload", maskedPayload->JSON.Encode.string), + ( + "headers", + headers + ->Array.map(header => { + let (key, value) = header + (key, value->JSON.Encode.string) + }) + ->Utils.getJsonFromArrayOfJson, + ), + ] + ->Utils.getJsonFromArrayOfJson + ->JSON.stringify + switch paymentType { + | Card => + handleLogging( + ~optLogger, + ~internalMetadata=loggerPayload, + ~value=contentLength, + ~eventName=PAYMENT_ATTEMPT, + ~paymentMethod="CARD", + ) + | _ => + bodyArr->Array.forEach(((str, json)) => { + if str === "payment_method_type" { + handleLogging( + ~optLogger, + ~value=contentLength, + ~internalMetadata=loggerPayload, + ~eventName=PAYMENT_ATTEMPT, + ~paymentMethod=json->getStringFromJson(""), + ) + } + () + }) + } + + intentCall( + ~fetchApi, + ~uri, + ~headers, + ~bodyStr=body, + ~confirmParam: ConfirmType.confirmParams, + ~clientSecret, + ~optLogger, + ~handleUserError, + ~paymentType, + ~iframeId, + ~fetchMethod=#POST, + ~setIsManualRetryEnabled, + ~customPodUri, + ~sdkHandleOneClickConfirmPayment=keys.sdkHandleOneClickConfirmPayment, + ~counter=0, + ) + ->then(val => { + intentCallback(val) + resolve() + }) + ->ignore + } + + let broswerInfo = BrowserSpec.broswerInfo + let intentWithoutMandate = mandatePaymentType => { + let bodyStr = + body + ->Array.concatMany([ + bodyArr->Array.concat(broswerInfo()), + mandatePaymentType->PaymentBody.paymentTypeBody, + ]) + ->Utils.getJsonFromArrayOfJson + ->JSON.stringify + callIntent(bodyStr) + } + + let intentWithMandate = mandatePaymentType => { + let bodyStr = + body + ->Array.concat( + bodyArr->Array.concatMany([PaymentBody.mandateBody(mandatePaymentType), broswerInfo()]), + ) + ->Utils.getJsonFromArrayOfJson + ->JSON.stringify + callIntent(bodyStr) + } + + switch paymentMethodList { + | LoadError(data) + | Loaded(data) => + let paymentList = data->getDictFromJson->PaymentMethodsRecord.itemToObjMapper + let mandatePaymentType = + paymentList.payment_type->PaymentMethodsRecord.paymentTypeToStringMapper + if paymentList.payment_methods->Array.length > 0 { + switch paymentList.mandate_payment { + | Some(_) => + switch paymentType { + | Card + | Gpay + | Applepay + | KlarnaRedirect + | Paypal + | BankDebits => + intentWithMandate(mandatePaymentType) + | _ => intentWithoutMandate(mandatePaymentType) + } + | None => intentWithoutMandate(mandatePaymentType) + } + } else { + postFailedSubmitResponse( + ~errortype="payment_methods_empty", + ~message="Payment Failed. Try again!", + ) + Console.warn("Please enable atleast one Payment method.") + } + | SemiLoaded => intentWithoutMandate("") + | _ => + postFailedSubmitResponse( + ~errortype="payment_methods_loading", + ~message="Please wait. Try again!", + ) + } + | None => + postFailedSubmitResponse( + ~errortype="post_session_tokens_failed", + ~message="Post Session Tokens failed. Try again!", + ) + } + } +} diff --git a/src/Utilities/PaymentUtils.res b/src/Utilities/PaymentUtils.res index 6422fb090..150978000 100644 --- a/src/Utilities/PaymentUtils.res +++ b/src/Utilities/PaymentUtils.res @@ -478,7 +478,7 @@ let sortCustomerMethodsBasedOnPriority = ( } let getSupportedCardBrands = ( - paymentMethodListValue: OrcaPaymentPage.PaymentMethodsRecord.paymentMethodList, + paymentMethodListValue: PaymentMethodsRecord.paymentMethodList, ) => { let cardPaymentMethod = paymentMethodListValue.payment_methods->Array.find(ele => ele.payment_method === "card") diff --git a/src/orca-log-catcher/OrcaLogger.res b/src/orca-log-catcher/OrcaLogger.res index bdcc4e4cb..82ab3933c 100644 --- a/src/orca-log-catcher/OrcaLogger.res +++ b/src/orca-log-catcher/OrcaLogger.res @@ -84,6 +84,8 @@ type eventName = | DELETE_PAYMENT_METHODS_CALL_INIT | DELETE_PAYMENT_METHODS_CALL | EXTERNAL_TAX_CALCULATION + | POST_SESSION_TOKENS_CALL + | POST_SESSION_TOKENS_CALL_INIT let eventNameToStrMapper = eventName => { switch eventName { @@ -168,6 +170,8 @@ let eventNameToStrMapper = eventName => { | DELETE_PAYMENT_METHODS_CALL_INIT => "DELETE_PAYMENT_METHODS_CALL_INIT" | DELETE_PAYMENT_METHODS_CALL => "DELETE_PAYMENT_METHODS_CALL" | EXTERNAL_TAX_CALCULATION => "EXTERNAL_TAX_CALCULATION" + | POST_SESSION_TOKENS_CALL => "POST_SESSION_TOKENS_CALL" + | POST_SESSION_TOKENS_CALL_INIT => "POST_SESSION_TOKENS_CALL_INIT" } } From 85bc6df60547ddb3d609f95a342f33c220962314 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 15 Oct 2024 15:10:26 +0000 Subject: [PATCH 8/8] chore(release): 0.94.2 [skip ci] ## [0.94.2](https://github.com/juspay/hyperswitch-web/compare/v0.94.1...v0.94.2) (2024-10-15) --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87f958649..7e8266a17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [0.94.2](https://github.com/juspay/hyperswitch-web/compare/v0.94.1...v0.94.2) (2024-10-15) + ## [0.94.1](https://github.com/juspay/hyperswitch-web/compare/v0.94.0...v0.94.1) (2024-10-15) diff --git a/package-lock.json b/package-lock.json index 4e5fc3453..57b209369 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.94.1", + "version": "0.94.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.94.1", + "version": "0.94.2", "hasInstallScript": true, "dependencies": { "@glennsl/rescript-fetch": "^0.2.0", diff --git a/package.json b/package.json index ddf8ff3eb..d7e353a44 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.94.1", + "version": "0.94.2", "main": "index.js", "private": true, "dependencies": {