From 56249ee3d0decc4f1e0a46b8033e6015036a2280 Mon Sep 17 00:00:00 2001 From: Kashif Date: Thu, 7 Nov 2024 16:45:54 +0530 Subject: [PATCH 1/2] refactor(redirection): allow redirections in root context (#774) Co-authored-by: Pritish Budhiraja Co-authored-by: Shiva Nandan --- src/Hooks/UtilityHooks.res | 14 ++++++++++++++ src/LoaderController.res | 8 ++++++++ src/Utilities/PaymentHelpers.res | 15 ++++++++++++++- src/Utilities/RecoilAtoms.res | 1 + src/Window.res | 19 ++++++++++++++++++- src/hyper-loader/Elements.res | 12 +++++++++--- src/hyper-loader/Hyper.res | 13 ++++++++++--- src/hyper-loader/LoaderPaymentElement.res | 3 ++- .../PaymentMethodsManagementElements.res | 1 + src/hyper-loader/PaymentSession.res | 2 ++ src/hyper-loader/PaymentSessionMethods.res | 5 +++++ 11 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/Hooks/UtilityHooks.res b/src/Hooks/UtilityHooks.res index ed06c76c5..ec1e28674 100644 --- a/src/Hooks/UtilityHooks.res +++ b/src/Hooks/UtilityHooks.res @@ -61,3 +61,17 @@ let useSendEventsToParent = eventsToSendToParent => { Some(() => {Window.removeEventListener("message", handle)}) }) } + +let useUpdateShouldUseTopRedirection = () => { + let setShouldUseTopRedirection = Recoil.useSetRecoilState(RecoilAtoms.shouldUseTopRedirectionAtom) + let updateTopRedirectionAtom = paymentOptions => { + paymentOptions + ->Dict.get("shouldUseTopRedirection") + ->Option.flatMap(JSON.Decode.bool) + ->Option.map(useTop => { + setShouldUseTopRedirection(_ => useTop) + }) + ->ignore + } + updateTopRedirectionAtom +} diff --git a/src/LoaderController.res b/src/LoaderController.res index b46360cbd..795c65a30 100644 --- a/src/LoaderController.res +++ b/src/LoaderController.res @@ -146,6 +146,8 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime } } + let updateShouldUseTopRedirection = UtilityHooks.useUpdateShouldUseTopRedirection() + React.useEffect0(() => { messageParentWindow([("iframeMounted", true->JSON.Encode.bool)]) messageParentWindow([ @@ -275,6 +277,9 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime }) logger.setClientSecret(clientSecret) + // Update top redirection atom + updateShouldUseTopRedirection(paymentOptions) + switch getThemePromise(paymentOptions) { | Some(promise) => promise->then(res => { @@ -322,6 +327,9 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime }) logger.setClientSecret(clientSecret) + // Update top redirection atom + updateShouldUseTopRedirection(paymentOptions) + switch getThemePromise(paymentOptions) { | Some(promise) => promise->then(res => { diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index 86dc02bc4..bd77583d6 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -295,6 +295,7 @@ let rec intentCall = ( ~isPaymentSession=false, ~isCallbackUsedVal=?, ~componentName="payment", + ~shouldUseTopRedirection, ) => { open Promise let isConfirm = uri->String.includes("/confirm") @@ -322,7 +323,7 @@ let rec intentCall = ( ) let handleOpenUrl = url => { if isPaymentSession { - Window.replaceRootHref(url) + Window.replaceRootHref(url, shouldUseTopRedirection) } else { openUrl(url) } @@ -448,6 +449,7 @@ let rec intentCall = ( ~sdkHandleOneClickConfirmPayment, ~counter=counter + 1, ~componentName, + ~shouldUseTopRedirection, ) ->then( res => { @@ -875,6 +877,7 @@ let rec intentCall = ( ~counter=counter + 1, ~isPaymentSession, ~componentName, + ~shouldUseTopRedirection, ) ->then( res => { @@ -905,6 +908,7 @@ let usePaymentSync = (optLogger: option, paymentType: pa let keys = Recoil.useRecoilValueFromAtom(keys) let isCallbackUsedVal = Recoil.useRecoilValueFromAtom(RecoilAtoms.isCompleteCallbackUsed) let customPodUri = Recoil.useRecoilValueFromAtom(customPodUri) + let shouldUseTopRedirection = Recoil.useRecoilValueFromAtom(shouldUseTopRedirectionAtom) let setIsManualRetryEnabled = Recoil.useSetRecoilState(isManualRetryEnabled) (~handleUserError=false, ~confirmParam: ConfirmType.confirmParams, ~iframeId="") => { switch keys.clientSecret { @@ -932,6 +936,7 @@ let usePaymentSync = (optLogger: option, paymentType: pa ~sdkHandleOneClickConfirmPayment=keys.sdkHandleOneClickConfirmPayment, ~counter=0, ~isCallbackUsedVal, + ~shouldUseTopRedirection, )->ignore } switch paymentMethodList { @@ -979,6 +984,7 @@ let usePaymentIntent = (optLogger, paymentType) => { let paymentMethodList = Recoil.useRecoilValueFromAtom(paymentMethodList) let keys = Recoil.useRecoilValueFromAtom(keys) let isCallbackUsedVal = Recoil.useRecoilValueFromAtom(RecoilAtoms.isCompleteCallbackUsed) + let shouldUseTopRedirection = Recoil.useRecoilValueFromAtom(shouldUseTopRedirectionAtom) let setIsManualRetryEnabled = Recoil.useSetRecoilState(isManualRetryEnabled) ( @@ -1074,6 +1080,7 @@ let usePaymentIntent = (optLogger, paymentType) => { ~counter=0, ~isCallbackUsedVal, ~componentName, + ~shouldUseTopRedirection, ) ->then(val => { intentCallback(val) @@ -1159,6 +1166,7 @@ let useCompleteAuthorize = (optLogger: option, paymentTy let setIsManualRetryEnabled = Recoil.useSetRecoilState(isManualRetryEnabled) let url = RescriptReactRouter.useUrl() let isCallbackUsedVal = Recoil.useRecoilValueFromAtom(RecoilAtoms.isCompleteCallbackUsed) + let shouldUseTopRedirection = Recoil.useRecoilValueFromAtom(shouldUseTopRedirectionAtom) let paymentTypeFromUrl = CardUtils.getQueryParamsDictforKey(url.search, "componentName")->CardThemeType.getPaymentMode ( @@ -1203,6 +1211,7 @@ let useCompleteAuthorize = (optLogger: option, paymentTy ~sdkHandleOneClickConfirmPayment=keys.sdkHandleOneClickConfirmPayment, ~counter=0, ~isCallbackUsedVal, + ~shouldUseTopRedirection, )->ignore } switch paymentMethodList { @@ -1595,6 +1604,7 @@ let paymentIntentForPaymentSession = ( ~clientSecret, ~logger, ~customPodUri, + ~shouldUseTopRedirection, ) => { let confirmParams = payload @@ -1651,6 +1661,7 @@ let paymentIntentForPaymentSession = ( ~sdkHandleOneClickConfirmPayment=false, ~counter=0, ~isPaymentSession=true, + ~shouldUseTopRedirection, ) } @@ -2087,6 +2098,7 @@ let usePostSessionTokens = ( let customPodUri = Recoil.useRecoilValueFromAtom(customPodUri) let paymentMethodList = Recoil.useRecoilValueFromAtom(paymentMethodList) let keys = Recoil.useRecoilValueFromAtom(keys) + let shouldUseTopRedirection = Recoil.useRecoilValueFromAtom(RecoilAtoms.shouldUseTopRedirectionAtom) let setIsManualRetryEnabled = Recoil.useSetRecoilState(isManualRetryEnabled) ( @@ -2178,6 +2190,7 @@ let usePostSessionTokens = ( ~customPodUri, ~sdkHandleOneClickConfirmPayment=keys.sdkHandleOneClickConfirmPayment, ~counter=0, + ~shouldUseTopRedirection, ) ->then(val => { intentCallback(val) diff --git a/src/Utilities/RecoilAtoms.res b/src/Utilities/RecoilAtoms.res index 414340f08..6ecce38ec 100644 --- a/src/Utilities/RecoilAtoms.res +++ b/src/Utilities/RecoilAtoms.res @@ -12,6 +12,7 @@ let sessionId = Recoil.atom("sessionId", "") let isConfirmBlocked = Recoil.atom("isConfirmBlocked", false) let customPodUri = Recoil.atom("customPodUri", "") let selectedOptionAtom = Recoil.atom("selectedOption", "") +let shouldUseTopRedirectionAtom = Recoil.atom("shouldUseTopRedirection", false) let paymentTokenAtom = Recoil.atom( "paymentToken", { diff --git a/src/Window.res b/src/Window.res index f2a17a768..4c4263247 100644 --- a/src/Window.res +++ b/src/Window.res @@ -205,4 +205,21 @@ let getRootHostName = () => } /* Redirect Handling */ -let replaceRootHref = (href: string) => Location.replace(href) +let replaceRootHref = (href: string, shouldUseTopRedirection: bool) => { + switch shouldUseTopRedirection { + | true => + try { + Top.Location.replace(href) + } catch { + | e => { + Js.Console.error3( + "Failed to redirect root document", + e, + `Using [window.location.replace] for redirection`, + ) + Location.replace(href) + } + } + | false => Location.replace(href) + } +} diff --git a/src/hyper-loader/Elements.res b/src/hyper-loader/Elements.res index ff44fb7fc..c49995a96 100644 --- a/src/hyper-loader/Elements.res +++ b/src/hyper-loader/Elements.res @@ -20,6 +20,7 @@ let make = ( ~logger: option, ~analyticsMetadata, ~customBackendUrl, + ~shouldUseTopRedirection, ) => { try { let iframeRef = [] @@ -310,6 +311,7 @@ let make = ( ("locale", locale), ("loader", loader), ("fonts", fonts), + ("shouldUseTopRedirection", shouldUseTopRedirection->JSON.Encode.bool), ]->getJsonFromArrayOfJson let message = [ ( @@ -667,7 +669,7 @@ let make = ( let returnUrl = dict->getString("return_url", "") let redirectUrl = `${returnUrl}?payment_intent_client_secret=${clientSecret}&status=${status}` if redirect.contents === "always" { - Window.replaceRootHref(redirectUrl) + Window.replaceRootHref(redirectUrl, shouldUseTopRedirection) resolve(JSON.Encode.null) } else { messageCurrentWindow([ @@ -695,7 +697,7 @@ let make = ( let handleErrorResponse = err => { if redirect.contents === "always" { - Window.replaceRootHref(url) + Window.replaceRootHref(url, shouldUseTopRedirection) } messageCurrentWindow([ ("submitSuccessful", false->JSON.Encode.bool), @@ -756,7 +758,10 @@ let make = ( ->then(json => json->handleRetrievePaymentResponse) ->catch(err => { if redirect.contents === "always" { - Window.replaceRootHref(redirectUrl->JSON.Decode.string->Option.getOr("")) + Window.replaceRootHref( + redirectUrl->JSON.Decode.string->Option.getOr(""), + shouldUseTopRedirection, + ) resolve(JSON.Encode.null) } else { messageCurrentWindow([ @@ -1157,6 +1162,7 @@ let make = ( setElementIframeRef, iframeRef, mountPostMessage, + ~shouldUseTopRedirection, ) savedPaymentElement->Dict.set(componentType, paymentElement) paymentElement diff --git a/src/hyper-loader/Hyper.res b/src/hyper-loader/Hyper.res index 347f05276..eac314c90 100644 --- a/src/hyper-loader/Hyper.res +++ b/src/hyper-loader/Hyper.res @@ -141,6 +141,11 @@ let make = (publishableKey, options: option, analyticsInfo: optionOption.getOr(JSON.Encode.null) ->Utils.getDictFromJson ->Utils.getBool("isPreloadEnabled", true) + let shouldUseTopRedirection = + options + ->Option.getOr(JSON.Encode.null) + ->Utils.getDictFromJson + ->Utils.getBool("shouldUseTopRedirection", false) let analyticsMetadata = options ->Option.getOr(JSON.Encode.null) @@ -393,9 +398,9 @@ let make = (publishableKey, options: option, analyticsInfo: optionJSON.Decode.bool->Option.getOr(false) if isSdkButton && submitSuccessfulValue { - Window.replaceRootHref(returnUrl) + Window.replaceRootHref(returnUrl, shouldUseTopRedirection) } else if submitSuccessfulValue && redirect === "always" { - Window.replaceRootHref(returnUrl) + Window.replaceRootHref(returnUrl, shouldUseTopRedirection) } else if !submitSuccessfulValue { resolve1(json) } else { @@ -487,6 +492,7 @@ let make = (publishableKey, options: option, analyticsInfo: optionOption.getOr(JSON.Encode.null) ->getDictFromJson ->getString("customBackendUrl", ""), + ~shouldUseTopRedirection, ) } @@ -572,7 +578,7 @@ let make = (publishableKey, options: option, analyticsInfo: optiongetString("return_url", "/") if val->JSON.Decode.bool->Option.getOr(false) && url !== "/" { - Window.replaceRootHref(url) + Window.replaceRootHref(url, shouldUseTopRedirection) } else { resolve(json) } @@ -669,6 +675,7 @@ let make = (publishableKey, options: option, analyticsInfo: option { try { let mountId = ref("") @@ -243,7 +244,7 @@ let make = ( switch eventDataObject->getOptionalJsonFromJson("openurl") { | Some(val) => { let url = val->getStringFromJson("") - Window.replaceRootHref(url) + Window.replaceRootHref(url, shouldUseTopRedirection) } | None => () } diff --git a/src/hyper-loader/PaymentMethodsManagementElements.res b/src/hyper-loader/PaymentMethodsManagementElements.res index 5b9a0ea11..fb033c66b 100644 --- a/src/hyper-loader/PaymentMethodsManagementElements.res +++ b/src/hyper-loader/PaymentMethodsManagementElements.res @@ -222,6 +222,7 @@ let make = ( iframeRef, mountPostMessage, ~isPaymentManagementElement=true, + ~shouldUseTopRedirection=false, ) savedPaymentElement->Dict.set(componentType, paymentElement) paymentElement diff --git a/src/hyper-loader/PaymentSession.res b/src/hyper-loader/PaymentSession.res index 78107c024..ddb0eb9b8 100644 --- a/src/hyper-loader/PaymentSession.res +++ b/src/hyper-loader/PaymentSession.res @@ -6,6 +6,7 @@ let make = ( ~publishableKey, ~logger: option, ~ephemeralKey, + ~shouldUseTopRedirection, ) => { let logger = logger->Option.getOr(HyperLogger.defaultLoggerConfig) let customPodUri = @@ -24,6 +25,7 @@ let make = ( ~endpoint, ~logger, ~customPodUri, + ~shouldUseTopRedirection, ), getPaymentManagementMethods: _ => PaymentSessionMethods.getPaymentManagementMethods( diff --git a/src/hyper-loader/PaymentSessionMethods.res b/src/hyper-loader/PaymentSessionMethods.res index fb80a5614..c54482a84 100644 --- a/src/hyper-loader/PaymentSessionMethods.res +++ b/src/hyper-loader/PaymentSessionMethods.res @@ -8,6 +8,7 @@ let getCustomerSavedPaymentMethods = ( ~endpoint, ~logger, ~customPodUri, + ~shouldUseTopRedirection, ) => { open ApplePayTypes open GooglePayType @@ -115,6 +116,7 @@ let getCustomerSavedPaymentMethods = ( ~clientSecret, ~logger, ~customPodUri, + ~shouldUseTopRedirection, ) } | None => @@ -163,6 +165,7 @@ let getCustomerSavedPaymentMethods = ( ~clientSecret, ~logger, ~customPodUri, + ~shouldUseTopRedirection, )->then(val => { val->resolvePromise resolve() @@ -231,6 +234,7 @@ let getCustomerSavedPaymentMethods = ( ~clientSecret, ~logger, ~customPodUri, + ~shouldUseTopRedirection, ) } @@ -305,6 +309,7 @@ let getCustomerSavedPaymentMethods = ( ~clientSecret, ~logger, ~customPodUri, + ~shouldUseTopRedirection, ) } | None => From efc7820aad70906db41395549a4925d5eb3d3a43 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 7 Nov 2024 11:18:19 +0000 Subject: [PATCH 2/2] chore(release): 0.101.4 [skip ci] ## [0.101.4](https://github.com/juspay/hyperswitch-web/compare/v0.101.3...v0.101.4) (2024-11-07) --- 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 3d0281313..47dd6de53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [0.101.4](https://github.com/juspay/hyperswitch-web/compare/v0.101.3...v0.101.4) (2024-11-07) + ## [0.101.3](https://github.com/juspay/hyperswitch-web/compare/v0.101.2...v0.101.3) (2024-11-07) ## [0.101.2](https://github.com/juspay/hyperswitch-web/compare/v0.101.1...v0.101.2) (2024-11-07) diff --git a/package-lock.json b/package-lock.json index 76d00eb7f..0bc63a4c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.101.3", + "version": "0.101.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.101.3", + "version": "0.101.4", "hasInstallScript": true, "dependencies": { "@glennsl/rescript-fetch": "^0.2.0", diff --git a/package.json b/package.json index d6b56eb7b..45ae91ba5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.101.3", + "version": "0.101.4", "main": "index.js", "private": true, "dependencies": {