React.useMemo(() => {
+ if displaySavedPaymentMethodsCheckbox {
+ isSaveCardsChecked || list.payment_type === SETUP_MANDATE
+ } else {
+ !(isGuestCustomer || list.payment_type === NORMAL)
+ }
+ }, (isSaveCardsChecked, list.payment_type, isGuestCustomer, displaySavedPaymentMethodsCheckbox))
diff --git a/src/LoaderController.res b/src/LoaderController.res
index 60e1430a5..e0b5a9aba 100644
--- a/src/LoaderController.res
+++ b/src/LoaderController.res
@@ -362,6 +362,15 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime
}
if dict->getDictIsSome("paymentMethodList") {
let list = dict->getJsonObjectFromDict("paymentMethodList")
+ let listDict = list->getDictFromJson
+ if optionsPayment.business.name === "" {
+ setOptionsPayment(prev => {
+ ...prev,
+ business: {
+ name: listDict->getString("merchant_name", ""),
+ },
+ })
+ }
let finalLoadLatency = if launchTime <= 0.0 {
-1.0
} else {
@@ -370,11 +379,11 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime
let updatedState: PaymentType.loadType =
list == Dict.make()->JSON.Encode.object
? LoadError(list)
- : switch list->getDictFromJson->Dict.get("error") {
+ : switch listDict->Dict.get("error") {
| Some(_) => LoadError(list)
| None =>
let isNonEmptyPaymentMethodList =
- list->getDictFromJson->getArray("payment_methods")->Array.length > 0
+ listDict->getArray("payment_methods")->Array.length > 0
isNonEmptyPaymentMethodList ? Loaded(list) : LoadError(list)
}
@@ -474,7 +483,7 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime
}
}
handleMessage(handleFun, "Error in parsing sent Data")
- }, (showCardFormByDefault, paymentMethodOrder))
+ }, (showCardFormByDefault, paymentMethodOrder, optionsPayment))
let observer = ResizeObserver.newResizerObserver(entries => {
entries
diff --git a/src/Payments/CardPayment.res b/src/Payments/CardPayment.res
index acccb7ea4..14aee6d5b 100644
--- a/src/Payments/CardPayment.res
+++ b/src/Payments/CardPayment.res
@@ -1,7 +1,5 @@
type target = {checked: bool}
type event = {target: target}
-open PaymentType
-open PaymentModeType
@react.component
let make = (
@@ -12,7 +10,11 @@ let make = (
~paymentType: CardThemeType.mode,
~list: PaymentMethodsRecord.list,
) => {
+ open PaymentType
+ open PaymentModeType
open Utils
+ open UtilityHooks
+
let {config, themeObj, localeString} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom)
let options = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom)
let loggerState = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom)
@@ -81,13 +83,9 @@ let make = (
None
}, [complete])
- UtilityHooks.useHandlePostMessages(
- ~complete=complete && areRequiredFieldsValid,
- ~empty,
- ~paymentType="card",
- )
+ useHandlePostMessages(~complete=complete && areRequiredFieldsValid, ~empty, ~paymentType="card")
- let isGuestCustomer = UtilityHooks.useIsGuestCustomer()
+ let isGuestCustomer = useIsGuestCustomer()
let isCvcValidValue = CardUtils.getBoolOptionVal(isCVCValid)
let (cardEmpty, cardComplete, cardInvalid) = CardUtils.useCardDetails(
~cvcNumber,
@@ -95,13 +93,12 @@ let make = (
~isCvcValidValue,
)
- let isCustomerAcceptanceRequired = React.useMemo(() => {
- if displaySavedPaymentMethodsCheckbox {
- isSaveCardsChecked || list.payment_type === SETUP_MANDATE
- } else {
- !(isGuestCustomer || list.payment_type === NORMAL)
- }
- }, (isSaveCardsChecked, list.payment_type))
+ let isCustomerAcceptanceRequired = useIsCustomerAcceptanceRequired(
+ ~displaySavedPaymentMethodsCheckbox,
+ ~isSaveCardsChecked,
+ ~list,
+ ~isGuestCustomer,
+ )
let submitCallback = React.useCallback((ev: Window.event) => {
let json = ev.data->JSON.parseExn
@@ -277,7 +274,9 @@ let make = (
/>
diff --git a/src/ThreeDSMethod.res b/src/ThreeDSMethod.res
index de218ada5..e024fd7a9 100644
--- a/src/ThreeDSMethod.res
+++ b/src/ThreeDSMethod.res
@@ -3,15 +3,25 @@ open Utils
let make = () => {
let logger = OrcaLogger.make()
- let mountToInnerHTML = innerHTML => {
- let ele = Window.querySelector("#threeDsInvisibleIframe")
- switch ele->Nullable.toOption {
- | Some(elem) => elem->Window.innerHTML(innerHTML)
- | None =>
- Console.warn(
- "INTEGRATION ERROR: Div does not seem to exist on which threeDSMethod is to be mounted",
- )
- }
+ let (stateMetadata, setStateMetadata) = React.useState(_ => Dict.make()->JSON.Encode.object)
+
+ let handleLoaded = _ev => {
+ stateMetadata->Utils.getDictFromJson->Dict.set("3dsMethodComp", "Y"->JSON.Encode.string)
+ let metadataDict = stateMetadata->JSON.Decode.object->Option.getOr(Dict.make())
+ let iframeId = metadataDict->getString("iframeId", "")
+ LoggerUtils.handleLogging(
+ ~optLogger=Some(logger),
+ ~eventName=THREE_DS_METHOD_RESULT,
+ ~value="Y",
+ ~paymentMethod="CARD",
+ (),
+ )
+ handlePostMessage([
+ ("fullscreen", true->JSON.Encode.bool),
+ ("param", `3dsAuth`->JSON.Encode.string),
+ ("iframeId", iframeId->JSON.Encode.string),
+ ("metadata", stateMetadata),
+ ])
}
React.useEffect0(() => {
@@ -21,6 +31,7 @@ let make = () => {
let dict = json->Utils.getDictFromJson
if dict->Dict.get("fullScreenIframeMounted")->Option.isSome {
let metadata = dict->getJsonObjectFromDict("metadata")
+ setStateMetadata(_ => metadata)
let metaDataDict = metadata->JSON.Decode.object->Option.getOr(Dict.make())
let threeDsDataDict =
metaDataDict
@@ -42,74 +53,65 @@ let make = () => {
->Option.getOr(Dict.make()->JSON.Encode.object)
let paymentIntentId = metaDataDict->Utils.getString("paymentIntentId", "")
let publishableKey = metaDataDict->Utils.getString("publishableKey", "")
- let iframeId = metaDataDict->getString("iframeId", "")
logger.setClientSecret(paymentIntentId)
logger.setMerchantId(publishableKey)
- open Promise
- PaymentHelpers.threeDsMethod(threeDsUrl, threeDsMethodData, ~optLogger=Some(logger))
- ->then(res => {
- if res == "" {
- Exn.raiseError("Empty response from threeDsMethod")->reject
- } else {
- LoggerUtils.handleLogging(
- ~optLogger=Some(logger),
- ~eventName=THREE_DS_METHOD_RESULT,
- ~value="Y",
- ~paymentMethod="CARD",
- (),
- )
- mountToInnerHTML(res)
- metadata->Utils.getDictFromJson->Dict.set("3dsMethodComp", "Y"->JSON.Encode.string)
- handlePostMessage([
- ("fullscreen", true->JSON.Encode.bool),
- ("param", `3dsAuth`->JSON.Encode.string),
- ("iframeId", iframeId->JSON.Encode.string),
- ("metadata", metadata),
- ])
- resolve(res)
- }
- })
- ->catch(err => {
- let exceptionMessage = err->Utils.formatException
- metadata->Utils.getDictFromJson->Dict.set("3dsMethodComp", "N"->JSON.Encode.string)
- handlePostMessage([
- ("fullscreen", true->JSON.Encode.bool),
- ("param", `3dsAuth`->JSON.Encode.string),
- ("iframeId", iframeId->JSON.Encode.string),
- ("metadata", metadata),
- ])
+ let iframeId = metaDataDict->getString("iframeId", "")
+
+ let handleFailureScenarios = value => {
LoggerUtils.handleLogging(
~optLogger=Some(logger),
~eventName=THREE_DS_METHOD_RESULT,
- ~value=exceptionMessage->JSON.stringify,
+ ~value,
~paymentMethod="CARD",
~logType=ERROR,
(),
)
- reject(err)
- })
- ->ignore
+ metadata->Utils.getDictFromJson->Dict.set("3dsMethodComp", "N"->JSON.Encode.string)
+ handlePostMessage([
+ ("fullscreen", true->JSON.Encode.bool),
+ ("param", `3dsAuth`->JSON.Encode.string),
+ ("iframeId", iframeId->JSON.Encode.string),
+ ("metadata", stateMetadata),
+ ])
+ }
- let headersDict =
- metaDataDict
- ->getJsonObjectFromDict("headers")
- ->JSON.Decode.object
- ->Option.getOr(Dict.make())
- let headers = Dict.make()
+ let ele = Window.querySelector("#threeDsInvisibleDiv")
- headersDict
- ->Dict.toArray
- ->Array.forEach(entries => {
- let (x, val) = entries
- Dict.set(headers, x, val->JSON.Decode.string->Option.getOr(""))
- })
+ switch ele->Nullable.toOption {
+ | Some(elem) => {
+ let form = elem->makeForm(threeDsUrl, "threeDsHiddenPostMethod")
+ let input = Types.createElement("input")
+ input.name = encodeURIComponent("threeDSMethodData")
+ let threeDsMethodStr = threeDsMethodData->JSON.Decode.string->Option.getOr("")
+ input.value = encodeURIComponent(threeDsMethodStr)
+ form.target = "threeDsInvisibleIframe"
+ form.appendChild(input)
+ try {
+ form.submit()
+ } catch {
+ | err => {
+ let exceptionMessage = err->Utils.formatException->JSON.stringify
+ handleFailureScenarios(exceptionMessage)
+ }
+ }
+ }
+ | None => handleFailureScenarios("Unable to Locate threeDsInvisibleDiv")
+ }
}
}
Window.addEventListener("message", handle)
Some(() => {Window.removeEventListener("message", handle)})
})
-
+ <>
+
+
+ >
}
diff --git a/src/Utilities/PaymentBody.res b/src/Utilities/PaymentBody.res
index 740d8c93f..e98bdacf3 100644
--- a/src/Utilities/PaymentBody.res
+++ b/src/Utilities/PaymentBody.res
@@ -64,7 +64,27 @@ let boletoBody = (~socialSecurityNumber) => [
),
]
-let savedCardBody = (~paymentToken, ~customerId, ~cvcNumber, ~requiresCvv) => {
+let customerAcceptanceBody =
+ [
+ ("acceptance_type", "online"->JSON.Encode.string),
+ ("accepted_at", Date.now()->Js.Date.fromFloat->Date.toISOString->JSON.Encode.string),
+ (
+ "online",
+ [("user_agent", BrowserSpec.navigator.userAgent->JSON.Encode.string)]
+ ->Dict.fromArray
+ ->JSON.Encode.object,
+ ),
+ ]
+ ->Dict.fromArray
+ ->JSON.Encode.object
+
+let savedCardBody = (
+ ~paymentToken,
+ ~customerId,
+ ~cvcNumber,
+ ~requiresCvv,
+ ~isCustomerAcceptanceRequired,
+) => {
let savedCardBody = [
("payment_method", "card"->JSON.Encode.string),
("payment_token", paymentToken->JSON.Encode.string),
@@ -75,29 +95,33 @@ let savedCardBody = (~paymentToken, ~customerId, ~cvcNumber, ~requiresCvv) => {
savedCardBody->Array.push(("card_cvc", cvcNumber->JSON.Encode.string))->ignore
}
+ if isCustomerAcceptanceRequired {
+ savedCardBody->Array.push(("customer_acceptance", customerAcceptanceBody))->ignore
+ }
+
savedCardBody
}
-let customerAcceptanceBody =
- [
- ("acceptance_type", "online"->JSON.Encode.string),
- ("accepted_at", Date.now()->Js.Date.fromFloat->Date.toISOString->JSON.Encode.string),
- (
- "online",
- [("user_agent", BrowserSpec.navigator.userAgent->JSON.Encode.string)]
- ->Dict.fromArray
- ->JSON.Encode.object,
- ),
+let savedPaymentMethodBody = (
+ ~paymentToken,
+ ~customerId,
+ ~paymentMethod,
+ ~paymentMethodType,
+ ~isCustomerAcceptanceRequired,
+) => {
+ let savedPaymentMethodBody = [
+ ("payment_method", paymentMethod->JSON.Encode.string),
+ ("payment_token", paymentToken->JSON.Encode.string),
+ ("customer_id", customerId->JSON.Encode.string),
+ ("payment_method_type", paymentMethodType),
]
- ->Dict.fromArray
- ->JSON.Encode.object
-let savedPaymentMethodBody = (~paymentToken, ~customerId, ~paymentMethod, ~paymentMethodType) => [
- ("payment_method", paymentMethod->JSON.Encode.string),
- ("payment_token", paymentToken->JSON.Encode.string),
- ("customer_id", customerId->JSON.Encode.string),
- ("payment_method_type", paymentMethodType),
-]
+ if isCustomerAcceptanceRequired {
+ savedPaymentMethodBody->Array.push(("customer_acceptance", customerAcceptanceBody))->ignore
+ }
+
+ savedPaymentMethodBody
+}
let mandateBody = paymentType => {
[
diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res
index 30a185cf5..d7746678e 100644
--- a/src/Utilities/PaymentHelpers.res
+++ b/src/Utilities/PaymentHelpers.res
@@ -79,69 +79,6 @@ let retrievePaymentIntent = (
})
}
-let threeDsMethod = (url, threeDsMethodData, ~optLogger) => {
- open Promise
- logApi(
- ~optLogger,
- ~url,
- ~apiLogType=Request,
- ~eventName=THREE_DS_METHOD_CALL_INIT,
- ~logType=INFO,
- ~logCategory=API,
- (),
- )
- let threeDsMethodStr = threeDsMethodData->JSON.Decode.string->Option.getOr("")
- let body = `${encodeURIComponent("threeDSMethodData")}=${encodeURIComponent(threeDsMethodStr)}`
-
- fetchApiWithNoCors(url, ~method=#POST, ~bodyStr=body, ())
- ->then(res => {
- let statusCode = res->Fetch.Response.status->Int.toString
- if statusCode->String.charAt(0) !== "2" {
- res
- ->Fetch.Response.text
- ->then(text => {
- logApi(
- ~optLogger,
- ~url,
- ~data=text->JSON.Encode.string,
- ~statusCode,
- ~apiLogType=Err,
- ~eventName=THREE_DS_METHOD_CALL,
- ~logType=ERROR,
- ~logCategory=API,
- (),
- )
- ""->resolve
- })
- } else {
- logApi(
- ~optLogger,
- ~url,
- ~statusCode,
- ~apiLogType=Response,
- ~eventName=THREE_DS_METHOD_CALL,
- (),
- )
- res->Fetch.Response.text
- }
- })
- ->catch(err => {
- let exceptionMessage = err->formatException
- Console.log2("Unable to call 3ds method ", exceptionMessage)
- logApi(
- ~optLogger,
- ~url,
- ~eventName=THREE_DS_METHOD_CALL,
- ~apiLogType=NoResponse,
- ~data=exceptionMessage,
- ~logType=ERROR,
- ~logCategory=API,
- (),
- )
- reject(err)
- })
-}
-
let threeDsAuth = (~clientSecret, ~optLogger, ~threeDsMethodComp, ~headers) => {
let endpoint = ApiEndpoint.getApiEndPoint()
let paymentIntentID = String.split(clientSecret, "_secret_")[0]->Option.getOr("")
diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res
index da69a2211..c3b8a2d00 100644
--- a/src/Utilities/Utils.res
+++ b/src/Utilities/Utils.res
@@ -835,37 +835,6 @@ let fetchApi = (uri, ~bodyStr: string="", ~headers=Dict.make(), ~method: Fetch.m
})
}
-let fetchApiWithNoCors = (
- uri,
- ~bodyStr: string="",
- ~headers=Dict.make(),
- ~method: Fetch.method,
- (),
-) => {
- open Promise
- let body = switch method {
- | #GET => resolve(None)
- | _ => resolve(Some(Fetch.Body.string(bodyStr)))
- }
- body->then(body => {
- Fetch.fetch(
- uri,
- {
- method,
- mode: #"no-cors",
- ?body,
- headers: getHeaders(~headers, ~uri, ()),
- },
- )
- ->catch(err => {
- reject(err)
- })
- ->then(resp => {
- resolve(resp)
- })
- })
-}
-
let arrayJsonToCamelCase = arr => {
arr->Array.map(item => {
item->transformKeys(CamelCase)
@@ -1192,7 +1161,7 @@ let makeForm = (element, url, id) => {
form.action = url
form.method = "POST"
form.enctype = "application/x-www-form-urlencoded;charset=UTF-8"
- form.style = "display: hidden; "
+ form.style = "display: hidden;"
element->appendChild(form)
form
}
diff --git a/src/orca-loader/Types.res b/src/orca-loader/Types.res
index 7800863c2..af364c201 100644
--- a/src/orca-loader/Types.res
+++ b/src/orca-loader/Types.res
@@ -177,8 +177,8 @@ type rec ele = {
mutable target: string,
mutable enctype: string,
mutable value: string,
- submit: (. unit) => unit,
- appendChild: (. ele) => unit,
+ submit: unit => unit,
+ appendChild: ele => unit,
}
@scope("document") @val external createElement: string => ele = "createElement"
diff --git a/src/orca-log-catcher/OrcaLogger.res b/src/orca-log-catcher/OrcaLogger.res
index 6517c1b09..c42ca30c2 100644
--- a/src/orca-log-catcher/OrcaLogger.res
+++ b/src/orca-log-catcher/OrcaLogger.res
@@ -14,8 +14,6 @@ type eventName =
| RETRIEVE_CALL
| AUTHENTICATION_CALL_INIT
| AUTHENTICATION_CALL
- | THREE_DS_METHOD_CALL_INIT
- | THREE_DS_METHOD_CALL
| CONFIRM_CALL_INIT
| CONFIRM_CALL
| SESSIONS_CALL_INIT
@@ -79,8 +77,6 @@ let eventNameToStrMapper = eventName => {
| RETRIEVE_CALL => "RETRIEVE_CALL"
| AUTHENTICATION_CALL_INIT => "AUTHENTICATION_CALL_INIT"
| AUTHENTICATION_CALL => "AUTHENTICATION_CALL"
- | THREE_DS_METHOD_CALL_INIT => "THREE_DS_METHOD_CALL_INIT"
- | THREE_DS_METHOD_CALL => "THREE_DS_METHOD_CALL"
| CONFIRM_CALL_INIT => "CONFIRM_CALL_INIT"
| CONFIRM_CALL => "CONFIRM_CALL"
| SESSIONS_CALL_INIT => "SESSIONS_CALL_INIT"
@@ -499,7 +495,7 @@ let make = (
PAYMENT_ATTEMPT,
CONFIRM_CALL,
AUTHENTICATION_CALL,
- THREE_DS_METHOD_CALL,
+ THREE_DS_METHOD_RESULT,
SDK_CRASH,
REDIRECTING_USER,
DISPLAY_BANK_TRANSFER_INFO_PAGE,
@@ -508,6 +504,7 @@ let make = (
LOADER_CHANGED,
SESSIONS_CALL,
RETRIEVE_CALL,
+ DISPLAY_THREE_DS_SDK,
]
arrayOfLogs
->Array.find(log => {
@@ -542,7 +539,6 @@ let make = (
}
}
| AUTHENTICATION_CALL
- | THREE_DS_METHOD_CALL
| RETRIEVE_CALL
| CONFIRM_CALL
| SESSIONS_CALL
diff --git a/webpack.common.js b/webpack.common.js
index f4d6b43b9..c8fc54102 100644
--- a/webpack.common.js
+++ b/webpack.common.js
@@ -11,6 +11,7 @@ const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");
const sdkEnv = process.env.sdkEnv;
const envSdkUrl = process.env.envSdkUrl;
const envBackendUrl = process.env.envBackendUrl;
+const envLoggingUrl = process.env.envLoggingUrl;
//git rev-parse --abbrev-ref HEAD
let repoVersion = require("./package.json").version;
@@ -62,10 +63,15 @@ if (envBackendUrl === undefined) {
confirmEndPoint = envBackendUrl;
}
-let logEndpoint =
- sdkEnv === "prod"
- ? "https://api.hyperswitch.io/logs/sdk"
- : "https://sandbox.hyperswitch.io/logs/sdk";
+let logEndpoint;
+if (envLoggingUrl === undefined) {
+ logEndpoint =
+ sdkEnv === "prod"
+ ? "https://api.hyperswitch.io/logs/sdk"
+ : "https://sandbox.hyperswitch.io/logs/sdk";
+} else {
+ logEndpoint = envLoggingUrl;
+}
// Set this to true to enable logging
let enableLogging = true;
diff --git a/webpack.dev.js b/webpack.dev.js
index ce80a9ad4..89044d741 100644
--- a/webpack.dev.js
+++ b/webpack.dev.js
@@ -16,6 +16,7 @@ let backendEndPoint =
let devServer = {
contentBase: path.join(__dirname, "dist"),
hot: true,
+ host: "0.0.0.0",
port: 9050,
historyApiFallback: true,
proxy: {