From d9a5b611dbb191f1e3f5a4504f3729249e60d73b Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Wed, 17 Apr 2024 14:10:06 +0530 Subject: [PATCH 01/11] fix: changes card payment (#306) --- src/Payments/CardPayment.res | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Payments/CardPayment.res b/src/Payments/CardPayment.res index bc22d7d85..f2a16c723 100644 --- a/src/Payments/CardPayment.res +++ b/src/Payments/CardPayment.res @@ -299,7 +299,9 @@ let make = ( | (Some(_), Auto, NEW_MANDATE) | (Some(_), Auto, SETUP_MANDATE) | (_, Always, NEW_MANDATE) - | (_, Always, SETUP_MANDATE) => + | (_, Always, SETUP_MANDATE) + | (_, _, SETUP_MANDATE) + | (_, _, NEW_MANDATE) =>
Date: Wed, 17 Apr 2024 08:41:49 +0000 Subject: [PATCH 02/11] chore(release): 0.42.2 [skip ci] ## [0.42.2](https://github.com/juspay/hyperswitch-web/compare/v0.42.1...v0.42.2) (2024-04-17) ### Bug Fixes * changes card payment ([#306](https://github.com/juspay/hyperswitch-web/issues/306)) ([d9a5b61](https://github.com/juspay/hyperswitch-web/commit/d9a5b611dbb191f1e3f5a4504f3729249e60d73b)) --- 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 19c52c408..3352d7561 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.42.2](https://github.com/juspay/hyperswitch-web/compare/v0.42.1...v0.42.2) (2024-04-17) + + +### Bug Fixes + +* changes card payment ([#306](https://github.com/juspay/hyperswitch-web/issues/306)) ([d9a5b61](https://github.com/juspay/hyperswitch-web/commit/d9a5b611dbb191f1e3f5a4504f3729249e60d73b)) + ## [0.42.1](https://github.com/juspay/hyperswitch-web/compare/v0.42.0...v0.42.1) (2024-04-17) diff --git a/package-lock.json b/package-lock.json index 7407a4771..25ec34d13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.42.1", + "version": "0.42.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.42.1", + "version": "0.42.2", "hasInstallScript": true, "dependencies": { "@aws-sdk/client-cloudfront": "^3.414.0", diff --git a/package.json b/package.json index 20f5e6ba3..57b61b217 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.42.1", + "version": "0.42.2", "main": "index.js", "private": true, "dependencies": { From 6494f517a95321b4cb0911f772866deff055d878 Mon Sep 17 00:00:00 2001 From: Praful Koppalkar <126236898+prafulkoppalkar@users.noreply.github.com> Date: Wed, 17 Apr 2024 14:50:05 +0530 Subject: [PATCH 03/11] fix: (paymenthelpers, paymentelement) promise being unresolved (#297) Co-authored-by: Pritish Budhiraja <1805317@kiit.ac.in> --- src/PaymentElement.res | 3 ++- src/Utilities/PaymentHelpers.res | 39 +++++++++++++++++++++----------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/PaymentElement.res b/src/PaymentElement.res index 756b3e19a..4f5048b99 100644 --- a/src/PaymentElement.res +++ b/src/PaymentElement.res @@ -398,7 +398,8 @@ let make = ( React.useEffect(() => { let evalMethodsList = () => switch methodslist { - | SemiLoaded | Loaded(_) => handlePostMessage([("ready", true->JSON.Encode.bool)]) + | SemiLoaded | LoadError(_) | Loaded(_) => + handlePostMessage([("ready", true->JSON.Encode.bool)]) | _ => () } if !displaySavedPaymentMethods { diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index 83937b42d..3042deedd 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -976,26 +976,39 @@ let usePaymentIntent = (optLogger: option, paymentType: p } switch list { + | LoadError(data) | Loaded(data) => let paymentList = data->getDictFromJson->PaymentMethodsRecord.itemToObjMapper let mandatePaymentType = paymentList.payment_type->PaymentMethodsRecord.paymentTypeToStringMapper - switch paymentList.mandate_payment { - | Some(_) => - switch paymentType { - | Card - | Gpay - | Applepay - | KlarnaRedirect - | Paypal - | BankDebits => - intentWithMandate(mandatePaymentType) - | _ => intentWithoutMandate(mandatePaymentType) + 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) } - | 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( From 38e8e8b1adffd889efaf9b0112963b4caf9d37e3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 17 Apr 2024 09:21:51 +0000 Subject: [PATCH 04/11] chore(release): 0.42.3 [skip ci] ## [0.42.3](https://github.com/juspay/hyperswitch-web/compare/v0.42.2...v0.42.3) (2024-04-17) ### Bug Fixes * (paymenthelpers, paymentelement) promise being unresolved ([#297](https://github.com/juspay/hyperswitch-web/issues/297)) ([6494f51](https://github.com/juspay/hyperswitch-web/commit/6494f517a95321b4cb0911f772866deff055d878)) --- 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 3352d7561..b26fe6ff4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.42.3](https://github.com/juspay/hyperswitch-web/compare/v0.42.2...v0.42.3) (2024-04-17) + + +### Bug Fixes + +* (paymenthelpers, paymentelement) promise being unresolved ([#297](https://github.com/juspay/hyperswitch-web/issues/297)) ([6494f51](https://github.com/juspay/hyperswitch-web/commit/6494f517a95321b4cb0911f772866deff055d878)) + ## [0.42.2](https://github.com/juspay/hyperswitch-web/compare/v0.42.1...v0.42.2) (2024-04-17) diff --git a/package-lock.json b/package-lock.json index 25ec34d13..c6f58f9fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.42.2", + "version": "0.42.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.42.2", + "version": "0.42.3", "hasInstallScript": true, "dependencies": { "@aws-sdk/client-cloudfront": "^3.414.0", diff --git a/package.json b/package.json index 57b61b217..0992f3ca5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.42.2", + "version": "0.42.3", "main": "index.js", "private": true, "dependencies": { From 03da57557f70ae36dc155392a6ccae2b9cad573e Mon Sep 17 00:00:00 2001 From: Praful Koppalkar <126236898+prafulkoppalkar@users.noreply.github.com> Date: Wed, 17 Apr 2024 15:07:07 +0530 Subject: [PATCH 05/11] fix: promise unresolved type error (#298) Co-authored-by: Vrishab Srivatsa <136090360+vsrivatsa-juspay@users.noreply.github.com> --- src/Utilities/PaymentHelpers.res | 121 +++++++++++++++++-------------- 1 file changed, 67 insertions(+), 54 deletions(-) diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index 3042deedd..ffddf3c10 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -712,65 +712,78 @@ let rec intentCall = ( }) ->catch(err => { Promise.make((resolve, _) => { - let url = urlSearch(confirmParam.return_url) - url.searchParams.set("payment_intent_client_secret", clientSecret) - url.searchParams.set("status", "failed") - let exceptionMessage = err->formatException - logApi( - ~optLogger, - ~url=uri, - ~eventName, - ~apiLogType=NoResponse, - ~data=exceptionMessage, - ~logType=ERROR, - ~logCategory=API, - ~isPaymentSession, - (), - ) - if counter >= 5 { - if !isPaymentSession { - closePaymentLoaderIfAny() - postFailedSubmitResponse(~errortype="server_error", ~message="Something went wrong") - } - if handleUserError { - handleOpenUrl(url.href) - } else { - let failedSubmitResponse = getFailedSubmitResponse( - ~errorType="server_error", - ~message="Something went wrong", - ) - resolve(failedSubmitResponse) - } - } else { - let paymentIntentID = String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("") - let endpoint = ApiEndpoint.getApiEndPoint(~publishableKey=confirmParam.publishableKey, ()) - let retrieveUri = `${endpoint}/payments/${paymentIntentID}?client_secret=${clientSecret}` - intentCall( - ~fetchApi, - ~uri=retrieveUri, - ~headers, - ~bodyStr, - ~confirmParam: ConfirmType.confirmParams, - ~clientSecret, + try { + let url = urlSearch(confirmParam.return_url) + url.searchParams.set("payment_intent_client_secret", clientSecret) + url.searchParams.set("status", "failed") + let exceptionMessage = err->formatException + logApi( ~optLogger, - ~handleUserError, - ~paymentType, - ~iframeId, - ~fetchMethod=#GET, - ~setIsManualRetryEnabled, - ~switchToCustomPod, - ~sdkHandleOneClickConfirmPayment, - ~counter=counter + 1, + ~url=uri, + ~eventName, + ~apiLogType=NoResponse, + ~data=exceptionMessage, + ~logType=ERROR, + ~logCategory=API, ~isPaymentSession, (), ) - ->then( - res => { - resolve(res) - Promise.resolve() - }, + if counter >= 5 { + if !isPaymentSession { + closePaymentLoaderIfAny() + postFailedSubmitResponse(~errortype="server_error", ~message="Something went wrong") + } + if handleUserError { + handleOpenUrl(url.href) + } else { + let failedSubmitResponse = getFailedSubmitResponse( + ~errorType="server_error", + ~message="Something went wrong", + ) + resolve(failedSubmitResponse) + } + } else { + let paymentIntentID = + String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("") + let endpoint = ApiEndpoint.getApiEndPoint(~publishableKey=confirmParam.publishableKey, ()) + let retrieveUri = `${endpoint}/payments/${paymentIntentID}?client_secret=${clientSecret}` + intentCall( + ~fetchApi, + ~uri=retrieveUri, + ~headers, + ~bodyStr, + ~confirmParam: ConfirmType.confirmParams, + ~clientSecret, + ~optLogger, + ~handleUserError, + ~paymentType, + ~iframeId, + ~fetchMethod=#GET, + ~setIsManualRetryEnabled, + ~switchToCustomPod, + ~sdkHandleOneClickConfirmPayment, + ~counter=counter + 1, + ~isPaymentSession, + (), + ) + ->then( + res => { + resolve(res) + Promise.resolve() + }, + ) + ->ignore + } + } catch { + | _ => + if !isPaymentSession { + postFailedSubmitResponse(~errortype="error", ~message="Something went wrong") + } + let failedSubmitResponse = getFailedSubmitResponse( + ~errorType="server_error", + ~message="Something went wrong", ) - ->ignore + resolve(failedSubmitResponse) } })->then(resolve) }) From 164a5acce9c1c703f75f847603493cf87b66e692 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 17 Apr 2024 09:38:57 +0000 Subject: [PATCH 06/11] chore(release): 0.42.4 [skip ci] ## [0.42.4](https://github.com/juspay/hyperswitch-web/compare/v0.42.3...v0.42.4) (2024-04-17) ### Bug Fixes * promise unresolved type error ([#298](https://github.com/juspay/hyperswitch-web/issues/298)) ([03da575](https://github.com/juspay/hyperswitch-web/commit/03da57557f70ae36dc155392a6ccae2b9cad573e)) --- 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 b26fe6ff4..7ea360db5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.42.4](https://github.com/juspay/hyperswitch-web/compare/v0.42.3...v0.42.4) (2024-04-17) + + +### Bug Fixes + +* promise unresolved type error ([#298](https://github.com/juspay/hyperswitch-web/issues/298)) ([03da575](https://github.com/juspay/hyperswitch-web/commit/03da57557f70ae36dc155392a6ccae2b9cad573e)) + ## [0.42.3](https://github.com/juspay/hyperswitch-web/compare/v0.42.2...v0.42.3) (2024-04-17) diff --git a/package-lock.json b/package-lock.json index c6f58f9fd..74f06d6c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.42.3", + "version": "0.42.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.42.3", + "version": "0.42.4", "hasInstallScript": true, "dependencies": { "@aws-sdk/client-cloudfront": "^3.414.0", diff --git a/package.json b/package.json index 0992f3ca5..024c07dc5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.42.3", + "version": "0.42.4", "main": "index.js", "private": true, "dependencies": { From ae177cb786ee8b64f17b79bd443d2912daf2f543 Mon Sep 17 00:00:00 2001 From: Vrishab Srivatsa <136090360+vsrivatsa-juspay@users.noreply.github.com> Date: Wed, 17 Apr 2024 15:44:09 +0530 Subject: [PATCH 07/11] refactor: Moved HTTP requests to within iframe (#128) Co-authored-by: Praful Koppalkar <126236898+prafulkoppalkar@users.noreply.github.com> --- ...perswitch_web_aws_production_deployment.sh | 6 +- aws/hyperswitch_web_aws_setup.sh | 12 +- src/App.res | 4 +- src/Payments/PreMountLoader.res | 177 ++-- src/Utilities/ApiEndpoint.res | 2 +- src/Utilities/PaymentHelpers.res | 2 +- src/Utilities/Utils.res | 11 + src/orca-loader/Elements.res | 906 +++++++++--------- src/orca-loader/Hyper.res | 3 +- src/orca-loader/PaymentSessionMethods.res | 2 +- webpack.common.js | 18 +- webpack.dev.js | 8 +- 12 files changed, 616 insertions(+), 535 deletions(-) diff --git a/aws/hyperswitch_web_aws_production_deployment.sh b/aws/hyperswitch_web_aws_production_deployment.sh index 0f3fdd9a6..62c9ed923 100755 --- a/aws/hyperswitch_web_aws_production_deployment.sh +++ b/aws/hyperswitch_web_aws_production_deployment.sh @@ -76,12 +76,12 @@ echo $( (aws s3api put-bucket-policy --bucket $MY_AWS_S3_BUCKET_NAME --policy "$ echo "Bucket configuration updated" -echo "Enter the backend endpoint your Hyperswitch Client will hit (hosted Hyperswitch Backend, https://sandbox.hyperswitch.io is taken by default):" +echo "Enter the backend endpoint your Hyperswitch Client will hit (hosted Hyperswitch Backend, https://beta.hyperswitch.io/api is taken by default):" read AWS_BACKEND_URL { let clientSecret = CardUtils.getQueryParamsDictforKey(url.search, "clientSecret") let sessionId = CardUtils.getQueryParamsDictforKey(url.search, "sessionId") let publishableKey = CardUtils.getQueryParamsDictforKey(url.search, "publishableKey") - let endpoint = - CardUtils.getQueryParamsDictforKey(url.search, "endpoint")->decodeURIComponent - + } | "achBankTransfer" | "bacsBankTransfer" diff --git a/src/Payments/PreMountLoader.res b/src/Payments/PreMountLoader.res index 214e2ecd0..ba75d49b1 100644 --- a/src/Payments/PreMountLoader.res +++ b/src/Payments/PreMountLoader.res @@ -1,83 +1,108 @@ @react.component -let make = (~sessionId as _, ~publishableKey as _, ~clientSecret as _, ~endpoint as _) => { - // open Utils - // let logger = OrcaLogger.make( - // ~sessionId, - // ~source=Loader, - // ~merchantId=publishableKey, - // ~clientSecret, - // (), - // ) +let make = (~sessionId, ~publishableKey, ~clientSecret) => { + open Utils + let (paymentMethodsResponseSent, setPaymentMethodsResponseSent) = React.useState(_ => false) + let ( + customerPaymentMethodsResponseSent, + setCustomerPaymentMethodsResponseSent, + ) = React.useState(_ => false) + let (sessionTokensResponseSent, setSessionTokensResponseSent) = React.useState(_ => false) + let logger = OrcaLogger.make( + ~sessionId, + ~source=Loader, + ~merchantId=publishableKey, + ~clientSecret, + (), + ) - // // let ( - // // paymentMethodsResponse, - // // customerPaymentMethodsResponse, - // // sessionTokensResponse, - // // ) = React.useMemo0(() => { - // // ( - // // PaymentHelpers.fetchPaymentMethodList( - // // ~clientSecret, - // // ~publishableKey, - // // ~logger, - // // ~switchToCustomPod=false, - // // ~endpoint, - // // ), - // // PaymentHelpers.fetchCustomerDetails( - // // ~clientSecret, - // // ~publishableKey, - // // ~optLogger=Some(logger), - // // ~switchToCustomPod=false, - // // ~endpoint, - // // ), - // // PaymentHelpers.fetchSessions( - // // ~clientSecret, - // // ~publishableKey, - // // ~optLogger=Some(logger), - // // ~switchToCustomPod=false, - // // ~endpoint, - // // (), - // // ), - // // ) - // // }) + let endpoint = ApiEndpoint.getApiEndPoint(~publishableKey, ()) - // // let sendPromiseData = (promise, key) => { - // // open Promise - // // promise - // // ->then(res => { - // // handlePostMessage([("response", res), ("data", key->JSON.Encode.string)]) - // // resolve() - // // }) - // // ->catch(_err => { - // // handlePostMessage([("response", JSON.Encode.null), ("data", key->JSON.Encode.string)]) - // // resolve() - // // }) - // // ->ignore - // // } + let paymentMethodsResponse = React.useMemo0(() => + PaymentHelpers.fetchPaymentMethodList( + ~clientSecret, + ~publishableKey, + ~logger, + ~switchToCustomPod=false, + ~endpoint, + ) + ) - // // React.useEffect0(() => { - // // let handle = (ev: Window.event) => { - // // let json = try { - // // ev.data->JSON.parseExn - // // } catch { - // // | _ => JSON.Encode.null - // // } - // // let dict = json->Utils.getDictFromJson - // // if dict->Dict.get("sendPaymentMethodsResponse")->Option.isSome { - // // paymentMethodsResponse->sendPromiseData("payment_methods") - // // } else if dict->Dict.get("sendCustomerPaymentMethodsResponse")->Option.isSome { - // // customerPaymentMethodsResponse->sendPromiseData("customer_payment_methods") - // // } else if dict->Dict.get("sendSessionTokensResponse")->Option.isSome { - // // sessionTokensResponse->sendPromiseData("session_tokens") - // // } - // // } - // // Window.addEventListener("message", handle) - // // handlePostMessage([("preMountLoaderInitCallback", true->JSON.Encode.bool)]) - // // Some( - // // () => { - // // Window.removeEventListener("message", handle) - // // }, - // // ) - // // }) + let customerPaymentMethodsResponse = React.useMemo0(() => + PaymentHelpers.fetchCustomerPaymentMethodList( + ~clientSecret, + ~publishableKey, + ~optLogger=Some(logger), + ~switchToCustomPod=false, + ~endpoint, + ) + ) + + let sessionTokensResponse = React.useMemo0(() => + PaymentHelpers.fetchSessions( + ~clientSecret, + ~publishableKey, + ~optLogger=Some(logger), + ~switchToCustomPod=false, + ~endpoint, + (), + ) + ) + + let sendPromiseData = (promise, key) => { + open Promise + promise + ->then(res => { + handlePostMessage([("response", res), ("data", key->JSON.Encode.string)]) + switch key { + | "payment_methods" => setPaymentMethodsResponseSent(_ => true) + | "session_tokens" => setSessionTokensResponseSent(_ => true) + | "customer_payment_methods" => setCustomerPaymentMethodsResponseSent(_ => true) + | _ => () + } + resolve() + }) + ->catch(_err => { + handlePostMessage([("response", JSON.Encode.null), ("data", key->JSON.Encode.string)]) + resolve() + }) + ->ignore + } + + let handle = (ev: Window.event) => { + let json = try { + ev.data->JSON.parseExn + } catch { + | _ => JSON.Encode.null + } + let dict = json->Utils.getDictFromJson + if dict->Dict.get("sendPaymentMethodsResponse")->Belt.Option.isSome { + paymentMethodsResponse->sendPromiseData("payment_methods") + } else if dict->Dict.get("sendCustomerPaymentMethodsResponse")->Belt.Option.isSome { + customerPaymentMethodsResponse->sendPromiseData("customer_payment_methods") + } else if dict->Dict.get("sendSessionTokensResponse")->Belt.Option.isSome { + sessionTokensResponse->sendPromiseData("session_tokens") + } + } + + React.useEffect0(() => { + Window.addEventListener("message", handle) + handlePostMessage([("preMountLoaderIframeMountedCallback", true->JSON.Encode.bool)]) + Some( + () => { + Window.removeEventListener("message", handle) + }, + ) + }) + + React.useEffect3(() => { + if ( + paymentMethodsResponseSent && customerPaymentMethodsResponseSent && sessionTokensResponseSent + ) { + handlePostMessage([("preMountLoaderIframeUnMount", true->JSON.Encode.bool)]) + Window.removeEventListener("message", handle) + } + None + }, (paymentMethodsResponseSent, customerPaymentMethodsResponseSent, sessionTokensResponseSent)) React.null } diff --git a/src/Utilities/ApiEndpoint.res b/src/Utilities/ApiEndpoint.res index 0bd259d16..d3ede5855 100644 --- a/src/Utilities/ApiEndpoint.res +++ b/src/Utilities/ApiEndpoint.res @@ -14,7 +14,7 @@ let getApiEndPoint = (~publishableKey="", ~isConfirmCall=false, ()) => { | Some(str) => str | None => let backendEndPoint = isConfirmCall ? GlobalVars.confirmEndPoint : GlobalVars.backendEndPoint - GlobalVars.isProd && testMode ? "https://sandbox.hyperswitch.io" : backendEndPoint + GlobalVars.isProd && testMode ? "https://beta.hyperswitch.io/api" : backendEndPoint } } diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index ffddf3c10..417274284 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -1194,7 +1194,7 @@ let fetchPaymentMethodList = ( }) } -let fetchCustomerDetails = ( +let fetchCustomerPaymentMethodList = ( ~clientSecret, ~publishableKey, ~endpoint, diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res index af84cfe38..da69a2211 100644 --- a/src/Utilities/Utils.res +++ b/src/Utilities/Utils.res @@ -1234,3 +1234,14 @@ let makeOneClickHandlerPromise = sdkHandleOneClickConfirmPayment => { } }) } + +let generateRandomString = length => { + let characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + let result = ref("") + let charactersLength = characters->String.length + Int.range(0, length)->Array.forEach(_ => { + let charIndex = mod((Math.random() *. 100.0)->Float.toInt, charactersLength) + result := result.contents ++ characters->String.charAt(charIndex) + }) + result.contents +} diff --git a/src/orca-loader/Elements.res b/src/orca-loader/Elements.res index d093d55a5..1297d5895 100644 --- a/src/orca-loader/Elements.res +++ b/src/orca-loader/Elements.res @@ -55,105 +55,135 @@ let make = ( ->Option.flatMap(JSON.Decode.bool) ->Option.getOr(false) - let paymentMethodListPromise = PaymentHelpers.fetchPaymentMethodList( - ~clientSecret, - ~publishableKey, - ~endpoint, - ~switchToCustomPod, - ~logger, - ) - - let customerDetailsPromise = PaymentHelpers.fetchCustomerDetails( - ~clientSecret, - ~publishableKey, - ~endpoint, - ~switchToCustomPod, - ~optLogger=Some(logger), - ) - - let sessionsPromise = PaymentHelpers.fetchSessions( - ~clientSecret, - ~publishableKey, - ~endpoint, - ~switchToCustomPod, - ~optLogger=Some(logger), - (), - ) + let localSelectorString = "hyper-preMountLoader-iframe" + let mountPreMountLoaderIframe = () => { + if ( + Window.querySelector( + `#orca-payment-element-iframeRef-${localSelectorString}`, + )->Js.Nullable.isNullable + ) { + let componentType = "preMountLoader" + let iframeDivHtml = `` + let iframeDiv = Window.createElement("div") + iframeDiv->Window.innerHTML(iframeDivHtml) + Window.body->Window.appendChild(iframeDiv) + } + + let elem = Window.querySelector(`#orca-payment-element-iframeRef-${localSelectorString}`) + elem + } let locale = localOptions->getJsonStringFromDict("locale", "") let loader = localOptions->getJsonStringFromDict("loader", "") let clientSecret = localOptions->getRequiredString("clientSecret", "", ~logger) - let clientSecretReMatch = RegExp.test(`.+_secret_[A-Za-z0-9]+`->RegExp.fromString, clientSecret) + let clientSecretReMatch = Re.test(`.+_secret_[A-Za-z0-9]+`->Re.fromString, clientSecret) + + let preMountLoaderIframeDiv = mountPreMountLoaderIframe() + + let unMountPreMountLoaderIframe = () => { + switch preMountLoaderIframeDiv->Nullable.toOption { + | Some(iframe) => iframe->remove + | None => () + } + } + + let preMountLoaderMountedPromise = Promise.make((resolve, _reject) => { + let preMountLoaderIframeCallback = (ev: Types.event) => { + let json = ev.data->Identity.anyTypeToJson + let dict = json->Utils.getDictFromJson + if dict->Dict.get("preMountLoaderIframeMountedCallback")->Belt.Option.isSome { + resolve(true->JSON.Encode.bool) + } else if dict->Dict.get("preMountLoaderIframeUnMount")->Belt.Option.isSome { + unMountPreMountLoaderIframe() + } + } + addSmartEventListener( + "message", + preMountLoaderIframeCallback, + "onPreMountLoaderIframeCallback", + ) + }) + let fetchPaymentsList = mountedIframeRef => { - open Promise - paymentMethodListPromise - ->then(json => { - let isApplePayPresent = - PaymentMethodsRecord.getPaymentMethodTypeFromList( - ~list=json->getDictFromJson->PaymentMethodsRecord.itemToObjMapper, - ~paymentMethod="wallet", - ~paymentMethodType="apple_pay", - )->Option.isSome - - let isGooglePayPresent = - PaymentMethodsRecord.getPaymentMethodTypeFromList( - ~list=json->getDictFromJson->PaymentMethodsRecord.itemToObjMapper, - ~paymentMethod="wallet", - ~paymentMethodType="google_pay", - )->Option.isSome - - if isApplePayPresent || isGooglePayPresent { - if ( - Window.querySelectorAll(`script[src="https://tpgw.trustpay.eu/js/v1.js"]`)->Array.length === 0 && - Window.querySelectorAll(`script[src="https://test-tpgw.trustpay.eu/js/v1.js"]`)->Array.length === 0 - ) { - let trustPayScriptURL = - publishableKey->String.startsWith("pk_prd_") - ? "https://tpgw.trustpay.eu/js/v1.js" - : "https://test-tpgw.trustpay.eu/js/v1.js" - let trustPayScript = Window.createElement("script") - trustPayScript->Window.elementSrc(trustPayScriptURL) - trustPayScript->Window.elementOnerror(err => { - logInfo(Console.log2("ERROR DURING LOADING TRUSTPAY APPLE PAY", err)) - }) - Window.body->Window.appendChild(trustPayScript) - logger.setLogInfo(~value="TrustPay Script Loaded", ~eventName=TRUSTPAY_SCRIPT, ()) + let handlePaymentMethodsLoaded = (event: Types.event) => { + let json = event.data->Identity.anyTypeToJson + let dict = json->getDictFromJson + let isPaymentMethodsData = dict->Utils.getString("data", "") === "payment_methods" + if isPaymentMethodsData { + let json = dict->Utils.getJsonFromDict("response", JSON.Encode.null) + let isApplePayPresent = + PaymentMethodsRecord.getPaymentMethodTypeFromList( + ~list=json->Utils.getDictFromJson->PaymentMethodsRecord.itemToObjMapper, + ~paymentMethod="wallet", + ~paymentMethodType="apple_pay", + )->Belt.Option.isSome + + let isGooglePayPresent = + PaymentMethodsRecord.getPaymentMethodTypeFromList( + ~list=json->Utils.getDictFromJson->PaymentMethodsRecord.itemToObjMapper, + ~paymentMethod="wallet", + ~paymentMethodType="google_pay", + )->Belt.Option.isSome + + if isApplePayPresent || isGooglePayPresent { + if ( + Window.querySelectorAll(`script[src="https://tpgw.trustpay.eu/js/v1.js"]`)->Array.length === 0 && + Window.querySelectorAll(`script[src="https://test-tpgw.trustpay.eu/js/v1.js"]`)->Array.length === 0 + ) { + let trustPayScriptURL = + publishableKey->String.startsWith("pk_prd_") + ? "https://tpgw.trustpay.eu/js/v1.js" + : "https://test-tpgw.trustpay.eu/js/v1.js" + let trustPayScript = Window.createElement("script") + trustPayScript->Window.elementSrc(trustPayScriptURL) + trustPayScript->Window.elementOnerror(err => { + Utils.logInfo(Console.log2("ERROR DURING LOADING TRUSTPAY APPLE PAY", err)) + }) + Window.body->Window.appendChild(trustPayScript) + logger.setLogInfo(~value="TrustPay Script Loaded", ~eventName=TRUSTPAY_SCRIPT, ()) + } + } + let msg = [("paymentMethodList", json)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + } + } + let msg = [("sendPaymentMethodsResponse", true->JSON.Encode.bool)]->Dict.fromArray + addSmartEventListener("message", handlePaymentMethodsLoaded, "onPaymentMethodsLoaded") + preMountLoaderIframeDiv->Window.iframePostMessage(msg) + } + let fetchCustomerPaymentMethods = (mountedIframeRef, disableSaveCards) => { + if !disableSaveCards { + let handleCustomerPaymentMethodsLoaded = (event: Types.event) => { + let json = event.data->Identity.anyTypeToJson + let dict = json->getDictFromJson + let isCustomerPaymentMethodsData = + dict->Utils.getString("data", "") === "customer_payment_methods" + if isCustomerPaymentMethodsData { + let json = dict->Utils.getJsonFromDict("response", JSON.Encode.null) + let msg = [("customerPaymentMethods", json)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) } } - - // setTimeout(() => { - let msg = [("paymentMethodList", json)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - let maskedPayload = json->PaymentHelpers.maskPayload->JSON.stringify - logger.setLogInfo( - ~value="", - ~internalMetadata=maskedPayload, - ~eventName=PAYMENT_METHODS_RESPONSE, - (), + addSmartEventListener( + "message", + handleCustomerPaymentMethodsLoaded, + "onCustomerPaymentMethodsLoaded", ) - // }, 5000)->ignore - json->resolve - }) - ->ignore - } - let fetchCustomerDetails = mountedIframeRef => { - open Promise - customerDetailsPromise - ->then(json => { - // setTimeout(() => { - let msg = [("customerPaymentMethods", json)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - // }, 5000)->ignore - json->resolve - }) - ->catch(_err => { - let dict = - [("customer_payment_methods", []->JSON.Encode.array)]->Dict.fromArray->JSON.Encode.object - let msg = [("customerPaymentMethods", dict)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - resolve(msg->JSON.Encode.object) - }) - ->ignore + } + let msg = + [ + ("sendCustomerPaymentMethodsResponse", !disableSaveCards->JSON.Encode.bool), + ]->Dict.fromArray + preMountLoaderIframeDiv->Window.iframePostMessage(msg) } !clientSecretReMatch @@ -246,7 +276,6 @@ let make = ( ("sdkSessionId", sdkSessionId->JSON.Encode.string), ("blockConfirm", blockConfirm->JSON.Encode.bool), ("switchToCustomPod", switchToCustomPod->JSON.Encode.bool), - ("endpoint", endpoint->JSON.Encode.string), ("sdkHandleOneClickConfirmPayment", sdkHandleOneClickConfirmPayment->JSON.Encode.bool), ("parentURL", "*"->JSON.Encode.string), ("analyticsMetadata", analyticsMetadata), @@ -396,372 +425,391 @@ let make = ( addSmartEventListener("message", handleApplePayMounted, "onApplePayMount") addSmartEventListener("message", handleGooglePayThirdPartyFlow, "onGooglePayThirdParty") + Window.removeEventListener("message", handleApplePayMessages.contents) - sessionsPromise - ->then(json => { - let sessionsArr = - json - ->JSON.Decode.object - ->Option.getOr(Dict.make()) - ->SessionsType.getSessionsTokenJson("session_token") - - let applePayPresent = sessionsArr->Array.find(item => { - let x = - item - ->JSON.Decode.object - ->Option.flatMap( - x => { - x->Dict.get("wallet_name") - }, - ) - ->Option.flatMap(JSON.Decode.string) - ->Option.getOr("") - x === "apple_pay" || x === "applepay" - }) - if !(applePayPresent->Option.isSome) { - let msg = [("applePaySessionObjNotPresent", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - } - let googlePayPresent = sessionsArr->Array.find(item => { - let x = - item - ->JSON.Decode.object - ->Option.flatMap( - x => { - x->Dict.get("wallet_name") - }, - ) - ->Option.flatMap(JSON.Decode.string) - ->Option.getOr("") - x === "google_pay" || x === "googlepay" - }) + let fetchSessionTokens = mountedIframeRef => { + let handleSessionTokensLoaded = (event: Types.event) => { + let json = event.data->Identity.anyTypeToJson + let dict = json->getDictFromJson + let sessionTokensData = dict->Utils.getString("data", "") === "session_tokens" + if sessionTokensData { + let json = dict->Utils.getJsonFromDict("response", JSON.Encode.null) - (json, applePayPresent, googlePayPresent)->resolve - }) - ->then(res => { - let (json, applePayPresent, googlePayPresent) = res - if componentType === "payment" && applePayPresent->Option.isSome { - //do operations here - let processPayment = (token: JSON.t) => { - //let body = PaymentBody.applePayBody(~token) - let msg = [("applePayProcessPayment", token)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - } + { + let sessionsArr = + json + ->JSON.Decode.object + ->Belt.Option.getWithDefault(Dict.make()) + ->SessionsType.getSessionsTokenJson("session_token") + + let applePayPresent = sessionsArr->Array.find(item => { + let x = + item + ->JSON.Decode.object + ->Belt.Option.flatMap(x => { + x->Dict.get("wallet_name") + }) + ->Belt.Option.flatMap(JSON.Decode.string) + ->Belt.Option.getWithDefault("") + x === "apple_pay" || x === "applepay" + }) + if !(applePayPresent->Belt.Option.isSome) { + let msg = + [("applePaySessionObjNotPresent", true->JSON.Encode.bool)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + } + let googlePayPresent = sessionsArr->Array.find(item => { + let x = + item + ->JSON.Decode.object + ->Belt.Option.flatMap(x => { + x->Dict.get("wallet_name") + }) + ->Belt.Option.flatMap(JSON.Decode.string) + ->Belt.Option.getWithDefault("") + x === "google_pay" || x === "googlepay" + }) - handleApplePayMessages := - ( - (event: Types.event) => { - let json = event.data->anyTypeToJson - let dict = json->getDictFromJson - switch dict->Dict.get("applePayButtonClicked") { - | Some(val) => - if val->JSON.Decode.bool->Option.getOr(false) { - let isDelayedSessionToken = - applePayPresent - ->Option.flatMap(JSON.Decode.object) - ->Option.getOr(Dict.make()) - ->Dict.get("delayed_session_token") - ->Option.getOr(JSON.Encode.null) - ->JSON.Decode.bool - ->Option.getOr(false) - - if isDelayedSessionToken { - logger.setLogInfo( - ~value="Delayed Session Token Flow", - ~eventName=APPLE_PAY_FLOW, - ~paymentMethod="APPLE_PAY", - (), - ) + (json, applePayPresent, googlePayPresent)->resolve + } + ->then(res => { + let (json, applePayPresent, googlePayPresent) = res + if componentType === "payment" && applePayPresent->Belt.Option.isSome { + //do operations here + let processPayment = (token: JSON.t) => { + //let body = PaymentBody.applePayBody(~token) + let msg = [("applePayProcessPayment", token)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + } - let applePayPresent = - dict - ->Dict.get("applePayPresent") - ->Option.flatMap(JSON.Decode.object) - ->Option.getOr(Dict.make()) - - let connector = - applePayPresent - ->Dict.get("connector") - ->Option.getOr(JSON.Encode.null) - ->JSON.Decode.string - ->Option.getOr("") - - switch connector { - | "trustpay" => - logger.setLogInfo( - ~value="TrustPay Connector Flow", - ~eventName=APPLE_PAY_FLOW, - ~paymentMethod="APPLE_PAY", - (), - ) - let secrets = - applePayPresent - ->Dict.get("session_token_data") - ->Option.getOr(JSON.Encode.null) - ->JSON.Decode.object - ->Option.getOr(Dict.make()) - ->Dict.get("secrets") - ->Option.getOr(JSON.Encode.null) - - let paymentRequest = - applePayPresent - ->Dict.get("payment_request_data") - ->Option.flatMap(JSON.Decode.object) - ->Option.getOr(Dict.make()) - ->jsonToPaymentRequestDataType - - let payment = - secrets - ->JSON.Decode.object - ->Option.getOr(Dict.make()) - ->Dict.get("payment") - ->Option.getOr(JSON.Encode.null) - ->JSON.Decode.string - ->Option.getOr("") - - try { - let trustpay = trustPayApi(secrets) - trustpay.finishApplePaymentV2(payment, paymentRequest) - ->then(res => { - logger.setLogInfo( - ~value="TrustPay ApplePay Success Response", - ~internalMetadata=res->JSON.stringify, - ~eventName=APPLE_PAY_FLOW, - ~paymentMethod="APPLE_PAY", - (), - ) - let msg = - [("applePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - resolve() - }) - ->catch(err => { - let exceptionMessage = err->formatException->JSON.stringify - logger.setLogInfo( - ~eventName=APPLE_PAY_FLOW, - ~paymentMethod="APPLE_PAY", - ~value=exceptionMessage, - (), - ) - let msg = - [("applePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - resolve() - }) - ->ignore - } catch { - | exn => { + handleApplePayMessages := + ( + (event: Types.event) => { + let json = event.data->Identity.anyTypeToJson + let dict = json->getDictFromJson + switch dict->Dict.get("applePayButtonClicked") { + | Some(val) => + if val->JSON.Decode.bool->Belt.Option.getWithDefault(false) { + let isDelayedSessionToken = + applePayPresent + ->Belt.Option.flatMap(JSON.Decode.object) + ->Belt.Option.getWithDefault(Dict.make()) + ->Dict.get("delayed_session_token") + ->Belt.Option.getWithDefault(JSON.Encode.null) + ->JSON.Decode.bool + ->Belt.Option.getWithDefault(false) + + if isDelayedSessionToken { logger.setLogInfo( - ~value=exn->formatException->JSON.stringify, + ~value="Delayed Session Token Flow", ~eventName=APPLE_PAY_FLOW, ~paymentMethod="APPLE_PAY", (), ) - let msg = - [("applePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + + let applePayPresent = + dict + ->Dict.get("applePayPresent") + ->Belt.Option.flatMap(JSON.Decode.object) + ->Belt.Option.getWithDefault(Dict.make()) + + let connector = + applePayPresent + ->Dict.get("connector") + ->Belt.Option.getWithDefault(JSON.Encode.null) + ->JSON.Decode.string + ->Belt.Option.getWithDefault("") + + switch connector { + | "trustpay" => + logger.setLogInfo( + ~value="TrustPay Connector Flow", + ~eventName=APPLE_PAY_FLOW, + ~paymentMethod="APPLE_PAY", + (), + ) + let secrets = + applePayPresent + ->Dict.get("session_token_data") + ->Belt.Option.getWithDefault(JSON.Encode.null) + ->JSON.Decode.object + ->Belt.Option.getWithDefault(Dict.make()) + ->Dict.get("secrets") + ->Belt.Option.getWithDefault(JSON.Encode.null) + + let paymentRequest = + applePayPresent + ->Dict.get("payment_request_data") + ->Belt.Option.flatMap(JSON.Decode.object) + ->Belt.Option.getWithDefault(Dict.make()) + ->ApplePayTypes.jsonToPaymentRequestDataType + + let payment = + secrets + ->JSON.Decode.object + ->Belt.Option.getWithDefault(Dict.make()) + ->Dict.get("payment") + ->Belt.Option.getWithDefault(JSON.Encode.null) + ->JSON.Decode.string + ->Belt.Option.getWithDefault("") + + try { + let trustpay = trustPayApi(secrets) + trustpay.finishApplePaymentV2(payment, paymentRequest) + ->then(res => { + logger.setLogInfo( + ~value="TrustPay ApplePay Success Response", + ~internalMetadata=res->JSON.stringify, + ~eventName=APPLE_PAY_FLOW, + ~paymentMethod="APPLE_PAY", + (), + ) + let msg = + [ + ("applePaySyncPayment", true->JSON.Encode.bool), + ]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + logger.setLogInfo( + ~value="", + ~eventName=PAYMENT_DATA_FILLED, + ~paymentMethod="APPLE_PAY", + (), + ) + resolve() + }) + ->catch(err => { + let exceptionMessage = + err->Utils.formatException->JSON.stringify + logger.setLogInfo( + ~eventName=APPLE_PAY_FLOW, + ~paymentMethod="APPLE_PAY", + ~value=exceptionMessage, + (), + ) + let msg = + [ + ("applePaySyncPayment", true->JSON.Encode.bool), + ]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + resolve() + }) + ->ignore + } catch { + | exn => { + logger.setLogInfo( + ~value=exn->Utils.formatException->JSON.stringify, + ~eventName=APPLE_PAY_FLOW, + ~paymentMethod="APPLE_PAY", + (), + ) + let msg = + [ + ("applePaySyncPayment", true->JSON.Encode.bool), + ]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + } + } + | _ => () + } + } else { + let paymentRequest = + applePayPresent + ->Belt.Option.flatMap(JSON.Decode.object) + ->Belt.Option.getWithDefault(Dict.make()) + ->Dict.get("payment_request_data") + ->Belt.Option.getWithDefault(Dict.make()->JSON.Encode.object) + ->Utils.transformKeys(Utils.CamelCase) + + let ssn = applePaySession(3, paymentRequest) + switch applePaySessionRef.contents->Nullable.toOption { + | Some(session) => + try { + session.abort() + } catch { + | error => Console.log2("Abort fail", error) + } + | None => () + } + + ssn.begin() + applePaySessionRef := ssn->Js.Nullable.return + + ssn.onvalidatemerchant = _event => { + let merchantSession = + applePayPresent + ->Belt.Option.flatMap(JSON.Decode.object) + ->Belt.Option.getWithDefault(Dict.make()) + ->Dict.get("session_token_data") + ->Belt.Option.getWithDefault(Dict.make()->JSON.Encode.object) + ->Utils.transformKeys(Utils.CamelCase) + ssn.completeMerchantValidation(merchantSession) + } + + ssn.onpaymentauthorized = event => { + ssn.completePayment( + {"status": ssn.\"STATUS_SUCCESS"}->Identity.anyTypeToJson, + ) + applePaySessionRef := Nullable.null + processPayment(event.payment.token) + } + ssn.oncancel = _ev => { + let msg = + [("showApplePayButton", true->JSON.Encode.bool)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + applePaySessionRef := Nullable.null + Utils.logInfo(Console.log("Apple Pay payment cancelled")) + } } + } else { + () } - | _ => () + | None => () } - } else { - try { - let paymentRequest = - applePayPresent - ->Option.flatMap(JSON.Decode.object) - ->Option.getOr(Dict.make()) - ->Dict.get("payment_request_data") - ->Option.getOr(Dict.make()->JSON.Encode.object) - ->transformKeys(CamelCase) - - let ssn = applePaySession(3, paymentRequest) - switch applePaySessionRef.contents->Nullable.toOption { - | Some(session) => - try { - session.abort() - } catch { - | error => Console.log2("Abort fail", error) - } - | None => () - } + } + ) - applePaySessionRef := ssn->Nullable.make + addSmartEventListener( + "message", + handleApplePayMessages.contents, + "onApplePayMessages", + ) + } + if componentType === "payment" && googlePayPresent->Belt.Option.isSome { + let dict = json->getDictFromJson + let sessionObj = SessionsType.itemToObjMapper(dict, Others) + let gPayToken = SessionsType.getPaymentSessionObj(sessionObj.sessionsToken, Gpay) - ssn.onvalidatemerchant = _event => { - let merchantSession = - applePayPresent - ->Option.flatMap(JSON.Decode.object) - ->Option.getOr(Dict.make()) - ->Dict.get("session_token_data") - ->Option.getOr(Dict.make()->JSON.Encode.object) - ->transformKeys(CamelCase) - ssn.completeMerchantValidation(merchantSession) - } + let tokenObj = switch gPayToken { + | OtherTokenOptional(optToken) => optToken + | _ => Some(SessionsType.defaultToken) + } - ssn.onpaymentauthorized = event => { - ssn.completePayment({"status": ssn.\"STATUS_SUCCESS"}->anyTypeToJson) - applePaySessionRef := Nullable.null - processPayment(event.payment.token) - } - ssn.oncancel = _ev => { - let msg = - [("showApplePayButton", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - applePaySessionRef := Nullable.null - logInfo(Console.log("Apple Pay payment cancelled")) - } + let gpayobj = switch tokenObj { + | Some(val) => val + | _ => SessionsType.defaultToken + } - ssn.begin() - } catch { - | exn => { - logger.setLogInfo( - ~value=exn->formatException->JSON.stringify, - ~eventName=APPLE_PAY_FLOW, - ~paymentMethod="APPLE_PAY", - (), - ) - logInfo(Console.error2("Apple Pay Error", exn)) - - let msg = - [("showApplePayButton", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - applePaySessionRef := Nullable.null - } - } - } - } else { - () - } - | None => () + let baseRequest = { + "apiVersion": 2, + "apiVersionMinor": 0, } - } - ) + let paymentDataRequest = GooglePayType.assign2( + Dict.make()->JSON.Encode.object, + baseRequest->Identity.anyTypeToJson, + ) - addSmartEventListener("message", handleApplePayMessages.contents, "onApplePayMessages") - } - if componentType === "payment" && googlePayPresent->Option.isSome { - let dict = json->getDictFromJson - let sessionObj = SessionsType.itemToObjMapper(dict, Others) - let gPayToken = SessionsType.getPaymentSessionObj(sessionObj.sessionsToken, Gpay) + let payRequest = GooglePayType.assign( + Dict.make()->JSON.Encode.object, + baseRequest->Identity.anyTypeToJson, + { + "allowedPaymentMethods": gpayobj.allowed_payment_methods->arrayJsonToCamelCase, + }->Identity.anyTypeToJson, + ) + paymentDataRequest.allowedPaymentMethods = + gpayobj.allowed_payment_methods->arrayJsonToCamelCase + paymentDataRequest.transactionInfo = + gpayobj.transaction_info->transformKeys(CamelCase) + paymentDataRequest.merchantInfo = gpayobj.merchant_info->transformKeys(CamelCase) + try { + let gPayClient = GooglePayType.google( + { + "environment": publishableKey->String.startsWith("pk_prd_") + ? "PRODUCTION" + : "TEST", + }->Identity.anyTypeToJson, + ) - let tokenObj = switch gPayToken { - | OtherTokenOptional(optToken) => optToken - | _ => Some(SessionsType.defaultToken) - } + gPayClient.isReadyToPay(payRequest) + ->then(res => { + let dict = res->getDictFromJson + let isReadyToPay = getBool(dict, "result", false) + let msg = [("isReadyToPay", isReadyToPay->JSON.Encode.bool)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + resolve() + }) + ->catch(err => { + logger.setLogInfo( + ~value=err->Identity.anyTypeToJson->JSON.stringify, + ~eventName=GOOGLE_PAY_FLOW, + ~paymentMethod="GOOGLE_PAY", + ~logType=DEBUG, + (), + ) + resolve() + }) + ->ignore - let gpayobj = switch tokenObj { - | Some(val) => val - | _ => SessionsType.defaultToken - } + let handleGooglePayMessages = (event: Types.event) => { + let evJson = event.data->anyTypeToJson + let gpayClicked = + evJson + ->getOptionalJsonFromJson("GpayClicked") + ->getBoolFromJson(false) + + if gpayClicked { + setTimeout(() => { + gPayClient.loadPaymentData(paymentDataRequest->anyTypeToJson) + ->then( + json => { + let msg = [("gpayResponse", json->anyTypeToJson)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + resolve() + }, + ) + ->catch( + err => { + logger.setLogInfo( + ~value=err->anyTypeToJson->JSON.stringify, + ~eventName=GOOGLE_PAY_FLOW, + ~paymentMethod="GOOGLE_PAY", + ~logType=DEBUG, + (), + ) - let baseRequest = { - "apiVersion": 2, - "apiVersionMinor": 0, - } - let paymentDataRequest = GooglePayType.assign2( - Dict.make()->JSON.Encode.object, - baseRequest->anyTypeToJson, - ) - - let payRequest = GooglePayType.assign( - Dict.make()->JSON.Encode.object, - baseRequest->anyTypeToJson, - { - "allowedPaymentMethods": gpayobj.allowed_payment_methods->arrayJsonToCamelCase, - }->anyTypeToJson, - ) - paymentDataRequest.allowedPaymentMethods = - gpayobj.allowed_payment_methods->arrayJsonToCamelCase - paymentDataRequest.transactionInfo = gpayobj.transaction_info->transformKeys(CamelCase) - paymentDataRequest.merchantInfo = gpayobj.merchant_info->transformKeys(CamelCase) - try { - let gPayClient = GooglePayType.google( - { - "environment": publishableKey->String.startsWith("pk_prd_") - ? "PRODUCTION" - : "TEST", - }->anyTypeToJson, - ) + let msg = [("gpayError", err->anyTypeToJson)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + resolve() + }, + ) + ->ignore + }, 0)->ignore + } + } + addSmartEventListener("message", handleGooglePayMessages, "onGooglePayMessages") + } catch { + | _ => Console.log("Error loading Gpay") + } + } - gPayClient.isReadyToPay(payRequest) - ->then(res => { - let dict = res->getDictFromJson - let isReadyToPay = getBool(dict, "result", false) - let msg = [("isReadyToPay", isReadyToPay->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - resolve() + json->resolve }) - ->catch(err => { - logger.setLogInfo( - ~value=err->anyTypeToJson->JSON.stringify, - ~eventName=GOOGLE_PAY_FLOW, - ~paymentMethod="GOOGLE_PAY", - ~logType=DEBUG, - (), - ) - resolve() + ->then(json => { + let msg = [("sessions", json)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + json->resolve }) ->ignore - - let handleGooglePayMessages = (event: Types.event) => { - let evJson = event.data->anyTypeToJson - let gpayClicked = - evJson - ->getOptionalJsonFromJson("GpayClicked") - ->getBoolFromJson(false) - - if gpayClicked { - setTimeout(() => { - gPayClient.loadPaymentData(paymentDataRequest->anyTypeToJson) - ->then( - json => { - let msg = [("gpayResponse", json->anyTypeToJson)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - resolve() - }, - ) - ->catch( - err => { - logger.setLogInfo( - ~value=err->anyTypeToJson->JSON.stringify, - ~eventName=GOOGLE_PAY_FLOW, - ~paymentMethod="GOOGLE_PAY", - ~logType=DEBUG, - (), - ) - - let msg = [("gpayError", err->anyTypeToJson)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - resolve() - }, - ) - ->ignore - }, 0)->ignore - } - } - addSmartEventListener("message", handleGooglePayMessages, "onGooglePayMessages") - } catch { - | _ => Console.log("Error loading Gpay") } } - - json->resolve - }) - ->then(json => { - let msg = [("sessions", json)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - json->resolve + let msg = [("sendSessionTokensResponse", true->JSON.Encode.bool)]->Dict.fromArray + addSmartEventListener("message", handleSessionTokensLoaded, "onSessionTokensLoaded") + preMountLoaderIframeDiv->Window.iframePostMessage(msg) + } + preMountLoaderMountedPromise + ->then(_ => { + fetchPaymentsList(mountedIframeRef) + if ( + newOptions + ->getDictFromJson + ->getBool("displaySavedPaymentMethods", true) + ) { + fetchCustomerPaymentMethods(mountedIframeRef, false) + } + fetchSessionTokens(mountedIframeRef) + mountedIframeRef->Window.iframePostMessage(message) + resolve() }) ->ignore - if ( - newOptions - ->getDictFromJson - ->getBool("displaySavedPaymentMethods", true) - ) { - fetchCustomerDetails(mountedIframeRef) - } - fetchPaymentsList(mountedIframeRef) - mountedIframeRef->Window.iframePostMessage(message) } let paymentElement = LoaderPaymentElement.make( diff --git a/src/orca-loader/Hyper.res b/src/orca-loader/Hyper.res index 1a8a955b8..b0388e068 100644 --- a/src/orca-loader/Hyper.res +++ b/src/orca-loader/Hyper.res @@ -85,7 +85,8 @@ let make = (publishableKey, options: option, analyticsInfo: optionOption.flatMap(JSON.Decode.object)->Option.getOr(Dict.make()) - let sessionID = analyticsInfoDict->getString("sessionID", "") + let sessionID = + analyticsInfoDict->getString("sessionID", "hyp_" ++ Utils.generateRandomString(8)) let sdkTimestamp = analyticsInfoDict->getString("timeStamp", Date.now()->Belt.Float.toString) let logger = OrcaLogger.make( ~sessionId=sessionID, diff --git a/src/orca-loader/PaymentSessionMethods.res b/src/orca-loader/PaymentSessionMethods.res index 8e5ab84a0..bdf2693ac 100644 --- a/src/orca-loader/PaymentSessionMethods.res +++ b/src/orca-loader/PaymentSessionMethods.res @@ -8,7 +8,7 @@ let getCustomerSavedPaymentMethods = ( ~switchToCustomPod, ) => { open Promise - PaymentHelpers.fetchCustomerDetails( + PaymentHelpers.fetchCustomerPaymentMethodList( ~clientSecret, ~publishableKey, ~endpoint, diff --git a/webpack.common.js b/webpack.common.js index c6602f654..f4d6b43b9 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -5,8 +5,7 @@ const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const CopyPlugin = require("copy-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const TerserPlugin = require("terser-webpack-plugin"); -const BundleAnalyzerPlugin = - require("webpack-bundle-analyzer").BundleAnalyzerPlugin; +const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; const { sentryWebpackPlugin } = require("@sentry/webpack-plugin"); const sdkEnv = process.env.sdkEnv; @@ -18,8 +17,7 @@ let repoVersion = require("./package.json").version; let majorVersion = "v" + repoVersion.split(".")[0]; let repoName = require("./package.json").name; -let repoPublicPath = - sdkEnv === "local" ? "" : `/${repoVersion}/${majorVersion}`; +let repoPublicPath = sdkEnv === "local" ? "" : `/${repoVersion}/${majorVersion}`; let sdkUrl; @@ -40,12 +38,12 @@ let backendEndPoint; if (envBackendUrl === undefined) { backendEndPoint = sdkEnv === "prod" - ? "https://api.hyperswitch.io" + ? "https://checkout.hyperswitch.io/api" : sdkEnv === "sandbox" - ? "https://sandbox.hyperswitch.io" + ? "https://beta.hyperswitch.io/api" : sdkEnv === "integ" ? "https://integ-api.hyperswitch.io" - : "https://sandbox.hyperswitch.io"; + : "https://beta.hyperswitch.io/api"; } else { backendEndPoint = envBackendUrl; } @@ -54,12 +52,12 @@ let confirmEndPoint; if (envBackendUrl === undefined) { confirmEndPoint = sdkEnv === "prod" - ? "https://api.hyperswitch.io" + ? "https://checkout.hyperswitch.io/api" : sdkEnv === "sandbox" - ? "https://sandbox.hyperswitch.io" + ? "https://beta.hyperswitch.io/api" : sdkEnv === "integ" ? "https://integ-api.hyperswitch.io" - : "https://sandbox.hyperswitch.io"; + : "https://beta.hyperswitch.io/api"; } else { confirmEndPoint = envBackendUrl; } diff --git a/webpack.dev.js b/webpack.dev.js index 8801754f3..ce80a9ad4 100644 --- a/webpack.dev.js +++ b/webpack.dev.js @@ -6,12 +6,12 @@ const sdkEnv = process.env.sdkEnv; let backendEndPoint = sdkEnv === "prod" - ? "https://api.hyperswitch.io/payments" + ? "https://checkout.hyperswitch.io/api/payments" : sdkEnv === "sandbox" - ? "https://sandbox.hyperswitch.io/payments" + ? "https://beta.hyperswitch.io/api/payments" : sdkEnv === "integ" ? "https://integ-api.hyperswitch.io/payments" - : "https://sandbox.hyperswitch.io/payments"; + : "https://beta.hyperswitch.io/api/payments"; let devServer = { contentBase: path.join(__dirname, "dist"), @@ -19,7 +19,7 @@ let devServer = { port: 9050, historyApiFallback: true, proxy: { - "/payments": { + "/api/payments": { target: backendEndPoint, changeOrigin: true, secure: true, From 30553d97a9bc5d34da56263160ba0affcea1d44d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 17 Apr 2024 10:16:50 +0000 Subject: [PATCH 08/11] chore(release): 0.42.5 [skip ci] ## [0.42.5](https://github.com/juspay/hyperswitch-web/compare/v0.42.4...v0.42.5) (2024-04-17) --- 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 7ea360db5..4b95efbf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [0.42.5](https://github.com/juspay/hyperswitch-web/compare/v0.42.4...v0.42.5) (2024-04-17) + ## [0.42.4](https://github.com/juspay/hyperswitch-web/compare/v0.42.3...v0.42.4) (2024-04-17) diff --git a/package-lock.json b/package-lock.json index 74f06d6c0..16da0cad1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.42.4", + "version": "0.42.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.42.4", + "version": "0.42.5", "hasInstallScript": true, "dependencies": { "@aws-sdk/client-cloudfront": "^3.414.0", diff --git a/package.json b/package.json index 024c07dc5..f3c53ed75 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.42.4", + "version": "0.42.5", "main": "index.js", "private": true, "dependencies": { From 51c98abc4da2438195cfbb7e418bf7f47f800008 Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Wed, 17 Apr 2024 18:33:36 +0530 Subject: [PATCH 09/11] fix: mandate data pass hide checkbox (#308) --- src/Payments/CardPayment.res | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Payments/CardPayment.res b/src/Payments/CardPayment.res index f2a16c723..acccb7ea4 100644 --- a/src/Payments/CardPayment.res +++ b/src/Payments/CardPayment.res @@ -183,6 +183,7 @@ let make = ( let paymentMethod = isBancontact ? "bank_redirect" : "card" let paymentMethodType = isBancontact ? "bancontact_card" : "debit" let conditionsForShowingSaveCardCheckbox = + list.mandate_payment->Option.isNone && !isGuestCustomer && list.payment_type !== SETUP_MANDATE && options.displaySavedPaymentMethodsCheckbox && @@ -190,8 +191,6 @@ let make = ( let nicknameFieldClassName = conditionsForShowingSaveCardCheckbox ? "pt-2" : "pt-5" - Js.log2("sdvjnsddsjd", (list.mandate_payment, options.terms.card)) -
Date: Wed, 17 Apr 2024 13:05:34 +0000 Subject: [PATCH 10/11] chore(release): 0.42.6 [skip ci] ## [0.42.6](https://github.com/juspay/hyperswitch-web/compare/v0.42.5...v0.42.6) (2024-04-17) ### Bug Fixes * mandate data pass hide checkbox ([#308](https://github.com/juspay/hyperswitch-web/issues/308)) ([51c98ab](https://github.com/juspay/hyperswitch-web/commit/51c98abc4da2438195cfbb7e418bf7f47f800008)) --- 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 4b95efbf6..48d862153 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.42.6](https://github.com/juspay/hyperswitch-web/compare/v0.42.5...v0.42.6) (2024-04-17) + + +### Bug Fixes + +* mandate data pass hide checkbox ([#308](https://github.com/juspay/hyperswitch-web/issues/308)) ([51c98ab](https://github.com/juspay/hyperswitch-web/commit/51c98abc4da2438195cfbb7e418bf7f47f800008)) + ## [0.42.5](https://github.com/juspay/hyperswitch-web/compare/v0.42.4...v0.42.5) (2024-04-17) ## [0.42.4](https://github.com/juspay/hyperswitch-web/compare/v0.42.3...v0.42.4) (2024-04-17) diff --git a/package-lock.json b/package-lock.json index 16da0cad1..36a57e68a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.42.5", + "version": "0.42.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.42.5", + "version": "0.42.6", "hasInstallScript": true, "dependencies": { "@aws-sdk/client-cloudfront": "^3.414.0", diff --git a/package.json b/package.json index f3c53ed75..6f3d563ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.42.5", + "version": "0.42.6", "main": "index.js", "private": true, "dependencies": { From 648ea87d8e2b0c989edbe7949b43a2c1e70e70cc Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Thu, 18 Apr 2024 13:04:57 +0530 Subject: [PATCH 11/11] feat: mandate changes for Saved Card flow (#309) Co-authored-by: Vrishab Srivatsa <136090360+vsrivatsa-juspay@users.noreply.github.com> Co-authored-by: Vrishab Srivatsa --- ...edCheckbox.res => SaveDetailsCheckbox.res} | 18 ++++-- src/Components/SavedMethods.res | 48 ++++++++++++-- src/Hooks/UtilityHooks.res | 13 ++++ src/LoaderController.res | 15 ++++- src/Payments/CardPayment.res | 31 +++++----- src/Utilities/PaymentBody.res | 62 +++++++++++++------ 6 files changed, 140 insertions(+), 47 deletions(-) rename src/Components/{AnimatedCheckbox.res => SaveDetailsCheckbox.res} (70%) diff --git a/src/Components/AnimatedCheckbox.res b/src/Components/SaveDetailsCheckbox.res similarity index 70% rename from src/Components/AnimatedCheckbox.res rename to src/Components/SaveDetailsCheckbox.res index 7a6fd1726..838fe86c8 100644 --- a/src/Components/AnimatedCheckbox.res +++ b/src/Components/SaveDetailsCheckbox.res @@ -1,12 +1,14 @@ @react.component let make = (~isChecked, ~setIsChecked) => { let {themeObj} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom) + let showFields = Recoil.useRecoilValueFromAtom(RecoilAtoms.showCardFieldsAtom) + let {business} = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom) + let css = `.container { display: flex; cursor: pointer; position: relative; justify-content: center; - align-items: center; } .container input { @@ -42,17 +44,23 @@ let make = (~isChecked, ~setIsChecked) => { setIsChecked(_ => value) } let {localeString} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom) - let (checkboxState, checkedState, checkBoxLabelSate) = isChecked + let (checkboxState, checkedState, checkBoxLabelState) = isChecked ? ("Checkbox--checked", "CheckboxInput--checked", "CheckboxLabel--checked") : ("", "", "") + let saveCardCheckboxLabel = if showFields { + localeString.saveCardDetails + } else { + localeString.cardTerms(business.name) + } +