From 82b44dd9f55bb4eb0848aa98621bed400fc7e21f Mon Sep 17 00:00:00 2001 From: Kashif Date: Fri, 9 Aug 2024 09:34:25 +0530 Subject: [PATCH 1/2] feat: handle child iframe redirections --- src/CollectWidget.res | 2 +- src/Utilities/PaymentHelpers.res | 2 +- src/Window.res | 125 ++++++++++++++++++++++- src/orca-loader/Elements.res | 20 ++-- src/orca-loader/Hyper.res | 6 +- src/orca-loader/LoaderPaymentElement.res | 2 +- 6 files changed, 139 insertions(+), 18 deletions(-) diff --git a/src/CollectWidget.res b/src/CollectWidget.res index f1be4802a..a28b90b0c 100644 --- a/src/CollectWidget.res +++ b/src/CollectWidget.res @@ -543,7 +543,7 @@ let make = ( value={pmt->getPaymentMethodTypeLabel} className="flex items-center px-2.5 py-0.5 cursor-pointer hover:bg-jp-gray-50" onClick={_ => handleTabSelection(pmt)}> -
{React.string(pmt->getPaymentMethodTypeLabel)}
+ {React.string(pmt->getPaymentMethodTypeLabel)} , ) } diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index 253f1a17b..de6476ea1 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -352,7 +352,7 @@ let rec intentCall = ( ) let handleOpenUrl = url => { if isPaymentSession { - Window.Location.replace(url) + Window.replaceRootHref(url) } else { openUrl(url) } diff --git a/src/Window.res b/src/Window.res index 10d4907aa..b35f3f913 100644 --- a/src/Window.res +++ b/src/Window.res @@ -14,8 +14,6 @@ type style @get external cardCVCElement: window => option = "cardCvc" @get external cardExpiryElement: window => option = "cardExpiry" @get external value: Dom.element => 'a = "value" -@val @scope(("window", "location")) -external replace: string => unit = "replace" @val @scope("document") external createElement: string => Dom.element = "createElement" @set external windowOnload: (window, unit => unit) => unit = "onload" @@ -131,6 +129,9 @@ module Location = { @val @scope(("window", "location")) external hostname: string = "hostname" + @val @scope(("window", "location")) + external href: string = "href" + @val @scope(("window", "location")) external origin: string = "origin" @@ -141,6 +142,50 @@ module Location = { external pathname: string = "pathname" } +module Parent = { + module Location = { + @val @scope(("window", "parent", "location")) + external replace: string => unit = "replace" + + @val @scope(("window", "parent", "location")) + external hostname: string = "hostname" + + @val @scope(("window", "parent", "location")) + external href: string = "href" + + @val @scope(("window", "parent", "location")) + external origin: string = "origin" + + @val @scope(("window", "parent", "location")) + external protocol: string = "protocol" + + @val @scope(("window", "parent", "location")) + external pathname: string = "pathname" + } +} + +module Top = { + module Location = { + @val @scope(("window", "top", "location")) + external replace: string => unit = "replace" + + @val @scope(("window", "top", "location")) + external hostname: string = "hostname" + + @val @scope(("window", "top", "location")) + external href: string = "href" + + @val @scope(("window", "top", "location")) + external origin: string = "origin" + + @val @scope(("window", "top", "location")) + external protocol: string = "protocol" + + @val @scope(("window", "top", "location")) + external pathname: string = "pathname" + } +} + module Element = { @get external clientWidth: Dom.element => int = "clientWidth" } @@ -155,3 +200,79 @@ let isSandbox = Location.hostname === "beta.hyperswitch.io" let isInteg = Location.hostname === "dev.hyperswitch.io" let isProd = Location.hostname === "checkout.hyperswitch.io" + +let isIframed = () => + try { + Location.href !== Top.Location.href + } catch { + | e => { + let default = true + Js.Console.error3( + "Failed to check whether or not document is within an iframe", + e, + `Using "${default->String.make}" as default (due to DOMException)`, + ) + default + } + } + +let isParentAndTopSame = () => + try { + Parent.Location.href === Top.Location.href + } catch { + | e => { + let default = false + Js.Console.error3( + "Failed to check whether or not parent and top were same", + e, + `Using "${default->String.make}" as default (due to DOMException)`, + ) + default + } + } + +let getRootHostName = () => + switch isIframed() { + | true => + try { + if isParentAndTopSame() { + Parent.Location.hostname + } else { + Top.Location.hostname + } + } catch { + | e => { + let default = Location.hostname + Js.Console.error3( + "Failed to get root document's hostname", + e, + `Using "${default}" [window.location.hostname] as default`, + ) + default + } + } + | false => Location.hostname + } + +let replaceRootHref = (href: string) => { + switch isIframed() { + | true => + try { + if isParentAndTopSame() { + Parent.Location.replace(href) + } else { + 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/orca-loader/Elements.res b/src/orca-loader/Elements.res index 32679f401..523d818cf 100644 --- a/src/orca-loader/Elements.res +++ b/src/orca-loader/Elements.res @@ -69,14 +69,14 @@ let make = ( let componentType = "preMountLoader" let iframeDivHtml = `` + + ` let iframeDiv = Window.createElement("div") iframeDiv->Window.innerHTML(iframeDivHtml) Window.body->Window.appendChild(iframeDiv) @@ -646,7 +646,7 @@ let make = ( let dict = json->getDictFromJson let status = dict->getString("status", "") let returnUrl = dict->getString("return_url", "") - Window.Location.replace( + Window.replaceRootHref( `${returnUrl}?payment_intent_client_secret=${clientSecret}&status=${status}`, ) resolve(JSON.Encode.null) @@ -661,7 +661,7 @@ let make = ( }) ->catch(err => { if redirect.contents === "always" { - Window.Location.replace(url) + Window.replaceRootHref(url) } handlePostMessage([ ("submitSuccessful", false->JSON.Encode.bool), diff --git a/src/orca-loader/Hyper.res b/src/orca-loader/Hyper.res index 42cb352eb..c3f5be69c 100644 --- a/src/orca-loader/Hyper.res +++ b/src/orca-loader/Hyper.res @@ -320,10 +320,10 @@ let make = (publishableKey, options: option, analyticsInfo: optionJSON.Decode.bool->Option.getOr(false)) { resolve1(json) } else { - Window.replace(returnUrl) + Window.replaceRootHref(returnUrl) } } else if val->JSON.Decode.bool->Option.getOr(false) && redirect === "always" { - Window.replace(returnUrl) + Window.replaceRootHref(returnUrl) } else if !(val->JSON.Decode.bool->Option.getOr(false)) { resolve1(json) } else { @@ -500,7 +500,7 @@ let make = (publishableKey, options: option, analyticsInfo: optiongetString("return_url", "/") if val->JSON.Decode.bool->Option.getOr(false) && url !== "/" { - Window.replace(url) + Window.replaceRootHref(url) } else { resolve(json) } diff --git a/src/orca-loader/LoaderPaymentElement.res b/src/orca-loader/LoaderPaymentElement.res index 7c6bdf2bc..adb7f7e2d 100644 --- a/src/orca-loader/LoaderPaymentElement.res +++ b/src/orca-loader/LoaderPaymentElement.res @@ -190,7 +190,7 @@ let make = ( switch eventDataObject->getOptionalJsonFromJson("openurl") { | Some(val) => { let url = val->getStringFromJson("") - Window.Location.replace(url) + Window.replaceRootHref(url) } | None => () } From 6103680eac2799fa8de95952e8fc37bb56b222b2 Mon Sep 17 00:00:00 2001 From: Kashif Date: Tue, 13 Aug 2024 14:29:06 +0530 Subject: [PATCH 2/2] refactor: remove window.parent --- src/Window.res | 49 ++----------------------------------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/src/Window.res b/src/Window.res index b35f3f913..6b4b754a0 100644 --- a/src/Window.res +++ b/src/Window.res @@ -142,28 +142,6 @@ module Location = { external pathname: string = "pathname" } -module Parent = { - module Location = { - @val @scope(("window", "parent", "location")) - external replace: string => unit = "replace" - - @val @scope(("window", "parent", "location")) - external hostname: string = "hostname" - - @val @scope(("window", "parent", "location")) - external href: string = "href" - - @val @scope(("window", "parent", "location")) - external origin: string = "origin" - - @val @scope(("window", "parent", "location")) - external protocol: string = "protocol" - - @val @scope(("window", "parent", "location")) - external pathname: string = "pathname" - } -} - module Top = { module Location = { @val @scope(("window", "top", "location")) @@ -216,30 +194,11 @@ let isIframed = () => } } -let isParentAndTopSame = () => - try { - Parent.Location.href === Top.Location.href - } catch { - | e => { - let default = false - Js.Console.error3( - "Failed to check whether or not parent and top were same", - e, - `Using "${default->String.make}" as default (due to DOMException)`, - ) - default - } - } - let getRootHostName = () => switch isIframed() { | true => try { - if isParentAndTopSame() { - Parent.Location.hostname - } else { - Top.Location.hostname - } + Top.Location.hostname } catch { | e => { let default = Location.hostname @@ -258,11 +217,7 @@ let replaceRootHref = (href: string) => { switch isIframed() { | true => try { - if isParentAndTopSame() { - Parent.Location.replace(href) - } else { - Top.Location.replace(href) - } + Top.Location.replace(href) } catch { | e => { Js.Console.error3(