-
-
-
-
-
String.length > 0}>
-
- {React.string(bankError)}
+ <>
+
+
+
+
+
+
+
+
+
+
String.length > 0}>
+
+ {React.string(bankError)}
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ >
}
let default = make
diff --git a/src/Payments/AddBankDetails.res b/src/Payments/AddBankDetails.res
new file mode 100644
index 000000000..5525fd905
--- /dev/null
+++ b/src/Payments/AddBankDetails.res
@@ -0,0 +1,104 @@
+module Loader = {
+ @react.component
+ let make = () => {
+ let {themeObj} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom)
+
+ }
+}
+
+@react.component
+let make = (~paymentMethodType) => {
+ open Utils
+ open Promise
+ let {publishableKey, clientSecret, iframeId} = Recoil.useRecoilValueFromAtom(RecoilAtoms.keys)
+ let {themeObj} = Recoil.useRecoilValueFromAtom(RecoilAtoms.configAtom)
+ let setOptionValue = Recoil.useSetRecoilState(RecoilAtoms.optionAtom)
+ let paymentMethodListValue = Recoil.useRecoilValueFromAtom(PaymentUtils.paymentMethodListValue)
+ let setShowFields = Recoil.useSetRecoilState(RecoilAtoms.showCardFieldsAtom)
+ let (showLoader, setShowLoader) = React.useState(() => false)
+
+ let pmAuthConnectorsArr =
+ PmAuthConnectorUtils.findPmAuthAllPMAuthConnectors(
+ paymentMethodListValue.payment_methods,
+ )->PmAuthConnectorUtils.getAllRequiredPmAuthConnectors
+
+ React.useEffect0(() => {
+ let onPlaidCallback = (ev: Window.event) => {
+ let json = ev.data->JSON.parseExn
+ let dict = json->Utils.getDictFromJson
+ if dict->getBool("isPlaid", false) {
+ let publicToken = dict->getDictFromDict("data")->getString("publicToken", "")
+ let isExited = dict->getDictFromDict("data")->getBool("isExited", false)
+ setShowLoader(_ => !isExited)
+ if publicToken->String.length > 0 {
+ PaymentHelpers.callAuthExchange(
+ ~publicToken,
+ ~clientSecret,
+ ~paymentMethodType,
+ ~publishableKey,
+ ~setOptionValue,
+ )
+ ->then(_ => {
+ handlePostMessage([("fullscreen", false->JSON.Encode.bool)])
+ setShowFields(_ => false)
+ JSON.Encode.null->resolve
+ })
+ ->catch(_ => JSON.Encode.null->resolve)
+ ->ignore
+ }
+ }
+ }
+
+ Window.addEventListener("message", onPlaidCallback)
+ Some(
+ () => {
+ Window.removeEventListener("message", ev => onPlaidCallback(ev))
+ },
+ )
+ })
+
+ let submitCallback = React.useCallback((ev: Window.event) => {
+ let json = ev.data->JSON.parseExn
+ let confirm = json->getDictFromJson->ConfirmType.itemToObjMapper
+ if confirm.doSubmit {
+ postFailedSubmitResponse(
+ ~errortype="validation_error",
+ ~message="Please add Bank Details and then confirm payment with the added payment methods.",
+ )
+ }
+ }, [])
+ useSubmitPaymentData(submitCallback)
+
+ let onClickHandler = () => {
+ setShowLoader(_ => true)
+ PaymentHelpers.callAuthLink(
+ ~publishableKey,
+ ~clientSecret,
+ ~iframeId,
+ ~paymentMethodType,
+ ~pmAuthConnectorsArr,
+ )->ignore
+ }
+
+
+}
diff --git a/src/Payments/PaymentMethodsRecord.res b/src/Payments/PaymentMethodsRecord.res
index 783173150..175032769 100644
--- a/src/Payments/PaymentMethodsRecord.res
+++ b/src/Payments/PaymentMethodsRecord.res
@@ -745,6 +745,7 @@ type paymentMethodTypes = {
bank_transfers_connectors: array
,
required_fields: array,
surcharge_details: option,
+ pm_auth_connector: option,
}
type methods = {
@@ -788,6 +789,7 @@ let defaultPaymentMethodType = {
bank_transfers_connectors: [],
required_fields: [],
surcharge_details: None,
+ pm_auth_connector: None,
}
let defaultList = {
@@ -935,6 +937,7 @@ let getPaymentMethodTypes = (dict, str) => {
paymentMethodType === "bancontact_card",
),
surcharge_details: jsonDict->getSurchargeDetails,
+ pm_auth_connector: getOptionString(jsonDict, "pm_auth_connector"),
}
})
}
diff --git a/src/Payments/PlaidSDKIframe.res b/src/Payments/PlaidSDKIframe.res
new file mode 100644
index 000000000..93d960c29
--- /dev/null
+++ b/src/Payments/PlaidSDKIframe.res
@@ -0,0 +1,78 @@
+@react.component
+let make = () => {
+ open Utils
+
+ let logger = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom)
+ let (linkToken, setLinkToken) = React.useState(_ => "")
+ let (isReady, setIsReady) = React.useState(_ => false)
+ let (pmAuthConnectorsArr, setPmAuthConnectorsArr) = React.useState(_ => [])
+
+ React.useEffect0(() => {
+ handlePostMessage([("iframeMountedCallback", true->JSON.Encode.bool)])
+ let handle = (ev: Window.event) => {
+ let json = ev.data->JSON.parseExn
+
+ let metaData = json->getDictFromJson->getDictFromDict("metadata")
+ let linkToken = metaData->getString("linkToken", "")
+ if linkToken->String.length > 0 {
+ let pmAuthConnectorArray =
+ metaData
+ ->getArray("pmAuthConnectorArray")
+ ->Array.map(ele => ele->JSON.Decode.string)
+
+ setLinkToken(_ => linkToken)
+ setPmAuthConnectorsArr(_ => pmAuthConnectorArray)
+ }
+ }
+ Window.addEventListener("message", handle)
+ Some(() => {Window.removeEventListener("message", handle)})
+ })
+
+ React.useEffect(() => {
+ PmAuthConnectorUtils.mountAllRequriedAuthConnectorScripts(
+ ~pmAuthConnectorsArr,
+ ~onScriptLoaded=authConnector => {
+ switch authConnector->PmAuthConnectorUtils.pmAuthNameToTypeMapper {
+ | PLAID => setIsReady(_ => true)
+ | NONE => ()
+ }
+ },
+ ~logger,
+ )
+ None
+ }, [pmAuthConnectorsArr])
+
+ React.useEffect(() => {
+ if isReady && linkToken->String.length > 0 {
+ let handler = Plaid.create({
+ token: linkToken,
+ onSuccess: (publicToken, _) => {
+ handlePostMessage([
+ ("isPlaid", true->JSON.Encode.bool),
+ ("publicToken", publicToken->JSON.Encode.string),
+ ])
+ },
+ onExit: _ => {
+ handlePostMessage([
+ ("fullscreen", false->JSON.Encode.bool),
+ ("isPlaid", true->JSON.Encode.bool),
+ ("isExited", true->JSON.Encode.bool),
+ ("publicToken", ""->JSON.Encode.string),
+ ])
+ },
+ })
+
+ handler.open_()
+ }
+
+ None
+ }, (isReady, linkToken))
+
+
+}
diff --git a/src/Payments/SepaBankDebit.res b/src/Payments/SepaBankDebit.res
index 0abe9cf9a..9a279c816 100644
--- a/src/Payments/SepaBankDebit.res
+++ b/src/Payments/SepaBankDebit.res
@@ -11,6 +11,8 @@ let make = (~paymentType: CardThemeType.mode) => {
let intent = PaymentHelpers.usePaymentIntent(Some(loggerState), BankDebits)
let {themeObj} = Recoil.useRecoilValueFromAtom(configAtom)
+ let {displaySavedPaymentMethods} = Recoil.useRecoilValueFromAtom(optionAtom)
+
let (modalData, setModalData) = React.useState(_ => None)
let (fullName, _) = Recoil.useLoggedRecoilState(userFullName, "fullName", loggerState)
@@ -22,6 +24,16 @@ let make = (~paymentType: CardThemeType.mode) => {
let (postalCode, _) = Recoil.useLoggedRecoilState(userAddressPincode, "postal_code", loggerState)
let (state, _) = Recoil.useLoggedRecoilState(userAddressState, "state", loggerState)
let setComplete = Recoil.useSetRecoilState(fieldsComplete)
+ let paymentMethodListValue = Recoil.useRecoilValueFromAtom(PaymentUtils.paymentMethodListValue)
+
+ let pmAuthMapper = React.useMemo1(
+ () =>
+ PmAuthConnectorUtils.findPmAuthAllPMAuthConnectors(paymentMethodListValue.payment_methods),
+ [paymentMethodListValue.payment_methods],
+ )
+
+ let isVerifyPMAuthConnectorConfigured =
+ displaySavedPaymentMethods && pmAuthMapper->Dict.get("sepa")->Option.isSome
let complete =
email.value != "" &&
@@ -82,21 +94,27 @@ let make = (~paymentType: CardThemeType.mode) => {
}
}, (email, fullName, modalData, isManualRetryEnabled))
useSubmitPaymentData(submitCallback)
-
-
+ <>
+
+
+
+
+
+
+ >
}
let default = make
diff --git a/src/Types/PaymentType.res b/src/Types/PaymentType.res
index ecb76617d..0f682e839 100644
--- a/src/Types/PaymentType.res
+++ b/src/Types/PaymentType.res
@@ -119,6 +119,7 @@ type customerCard = {
cardHolderName: option,
nickname: string,
}
+type bank = {mask: string}
type customerMethods = {
paymentToken: string,
customerId: string,
@@ -130,6 +131,7 @@ type customerMethods = {
defaultPaymentMethodSet: bool,
requiresCvv: bool,
lastUsedAt: string,
+ bank: bank,
}
type savedCardsLoadState =
LoadingSavedCards | LoadedSavedCards(array, bool) | NoResult(bool)
@@ -189,6 +191,7 @@ let defaultCustomerMethods = {
defaultPaymentMethodSet: false,
requiresCvv: true,
lastUsedAt: "",
+ bank: {mask: ""},
}
let defaultLayout = {
defaultCollapsed: false,
@@ -851,18 +854,18 @@ let getPaymentMethodType = dict => {
dict->Dict.get("payment_method_type")->Option.flatMap(JSON.Decode.string)
}
+let getBank = dict => {
+ {
+ mask: dict
+ ->getDictFromDict("bank")
+ ->getString("mask", ""),
+ }
+}
+
let itemToCustomerObjMapper = customerDict => {
- let customerArr =
- customerDict
- ->Dict.get("customer_payment_methods")
- ->Option.flatMap(JSON.Decode.array)
- ->Option.getOr([])
+ let customerArr = customerDict->getArray("customer_payment_methods")
- let isGuestCustomer =
- customerDict
- ->Dict.get("is_guest_customer")
- ->Option.flatMap(JSON.Decode.bool)
- ->Option.getOr(false)
+ let isGuestCustomer = customerDict->getBool("is_guest_customer", false)
let customerPaymentMethods =
customerArr
@@ -879,6 +882,7 @@ let itemToCustomerObjMapper = customerDict => {
defaultPaymentMethodSet: getBool(dict, "default_payment_method_set", false),
requiresCvv: getBool(dict, "requires_cvv", true),
lastUsedAt: getString(dict, "last_used_at", ""),
+ bank: dict->getBank,
}
})
@@ -914,6 +918,7 @@ let getCustomerMethods = (dict, str) => {
defaultPaymentMethodSet: getBool(dict, "default_payment_method_set", false),
requiresCvv: getBool(dict, "requires_cvv", true),
lastUsedAt: getString(dict, "last_used_at", ""),
+ bank: dict->getBank,
}
})
LoadedSavedCards(customerPaymentMethods, false)
diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res
index a8f0539aa..67b7241b0 100644
--- a/src/Utilities/PaymentHelpers.res
+++ b/src/Utilities/PaymentHelpers.res
@@ -30,7 +30,7 @@ type paymentIntent = (
~iframeId: string=?,
~isThirdPartyFlow: bool=?,
~intentCallback: Core__JSON.t => unit=?,
- ~manualRetry:bool=?,
+ ~manualRetry: bool=?,
unit,
) => unit
@@ -50,7 +50,7 @@ let retrievePaymentIntent = (
~isForceSync=false,
) => {
open Promise
- let paymentIntentID = String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("")
+ let paymentIntentID = clientSecret->getPaymentId
let endpoint = ApiEndpoint.getApiEndPoint()
let forceSync = isForceSync ? "&force_sync=true" : ""
let uri = `${endpoint}/payments/${paymentIntentID}?client_secret=${clientSecret}${forceSync}`
@@ -490,8 +490,7 @@ let rec intentCall = (
resolve(failedSubmitResponse)
}
} else {
- let paymentIntentID =
- String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("")
+ let paymentIntentID = clientSecret->getPaymentId
let endpoint = ApiEndpoint.getApiEndPoint(
~publishableKey=confirmParam.publishableKey,
~isConfirmCall=isConfirm,
@@ -880,8 +879,7 @@ let rec intentCall = (
resolve(failedSubmitResponse)
}
} else {
- let paymentIntentID =
- String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("")
+ let paymentIntentID = clientSecret->getPaymentId
let endpoint = ApiEndpoint.getApiEndPoint(
~publishableKey=confirmParam.publishableKey,
~isConfirmCall=isConfirm,
@@ -939,7 +937,7 @@ let usePaymentSync = (optLogger: option, paymentType: pay
(~handleUserError=false, ~confirmParam: ConfirmType.confirmParams, ~iframeId="", ()) => {
switch keys.clientSecret {
| Some(clientSecret) =>
- let paymentIntentID = String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("")
+ let paymentIntentID = clientSecret->getPaymentId
let headers = [("Content-Type", "application/json"), ("api-key", confirmParam.publishableKey)]
let endpoint = ApiEndpoint.getApiEndPoint(~publishableKey=confirmParam.publishableKey, ())
let uri = `${endpoint}/payments/${paymentIntentID}?force_sync=true&client_secret=${clientSecret}`
@@ -1022,16 +1020,14 @@ let usePaymentIntent = (optLogger, paymentType) => {
) => {
switch keys.clientSecret {
| Some(clientSecret) =>
- let paymentIntentID = String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("")
+ let paymentIntentID = clientSecret->getPaymentId
let headers = [
("Content-Type", "application/json"),
("api-key", confirmParam.publishableKey),
("X-Client-Source", paymentTypeFromUrl->CardThemeType.getPaymentModeToStrMapper),
]
let returnUrlArr = [("return_url", confirmParam.return_url->JSON.Encode.string)]
- let manual_retry = manualRetry
- ? [("retry_action", "manual_retry"->JSON.Encode.string)]
- : []
+ let manual_retry = manualRetry ? [("retry_action", "manual_retry"->JSON.Encode.string)] : []
let body =
[("client_secret", clientSecret->JSON.Encode.string)]->Array.concatMany([
returnUrlArr,
@@ -1203,7 +1199,7 @@ let useCompleteAuthorize = (optLogger: option, paymentTyp
) => {
switch keys.clientSecret {
| Some(clientSecret) =>
- let paymentIntentID = String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("")
+ let paymentIntentID = clientSecret->getPaymentId
let headers = [
("Content-Type", "application/json"),
("api-key", confirmParam.publishableKey),
@@ -1265,7 +1261,7 @@ let fetchSessions = (
) => {
open Promise
let headers = [("Content-Type", "application/json"), ("api-key", publishableKey)]
- let paymentIntentID = String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("")
+ let paymentIntentID = clientSecret->getPaymentId
let body =
[
("payment_id", paymentIntentID->JSON.Encode.string),
@@ -1717,3 +1713,134 @@ let paymentIntentForPaymentSession = (
(),
)
}
+
+let callAuthLink = (
+ ~publishableKey,
+ ~clientSecret,
+ ~paymentMethodType,
+ ~pmAuthConnectorsArr,
+ ~iframeId,
+) => {
+ open Promise
+ let endpoint = ApiEndpoint.getApiEndPoint()
+ let uri = `${endpoint}/payment_methods/auth/link`
+ let headers = [("Content-Type", "application/json"), ("api-key", publishableKey)]->Dict.fromArray
+
+ fetchApi(
+ uri,
+ ~method=#POST,
+ ~bodyStr=[
+ ("client_secret", clientSecret->Option.getOr("")->JSON.Encode.string),
+ ("payment_id", clientSecret->Option.getOr("")->getPaymentId->JSON.Encode.string),
+ ("payment_method", "bank_debit"->JSON.Encode.string),
+ ("payment_method_type", paymentMethodType->JSON.Encode.string),
+ ]
+ ->getJsonFromArrayOfJson
+ ->JSON.stringify,
+ ~headers,
+ (),
+ )
+ ->then(res => {
+ let statusCode = res->Fetch.Response.status->Int.toString
+ if statusCode->String.charAt(0) !== "2" {
+ res
+ ->Fetch.Response.json
+ ->then(_ => {
+ JSON.Encode.null->resolve
+ })
+ } else {
+ res
+ ->Fetch.Response.json
+ ->then(data => {
+ let metaData =
+ [
+ ("linkToken", data->getDictFromJson->getString("link_token", "")->JSON.Encode.string),
+ ("pmAuthConnectorArray", pmAuthConnectorsArr->Identity.anyTypeToJson),
+ ]->getJsonFromArrayOfJson
+
+ handlePostMessage([
+ ("fullscreen", true->JSON.Encode.bool),
+ ("param", "plaidSDK"->JSON.Encode.string),
+ ("iframeId", iframeId->JSON.Encode.string),
+ ("metadata", metaData),
+ ])
+ JSON.Encode.null->resolve
+ })
+ }
+ })
+ ->catch(e => {
+ Console.log2("Unable to retrieve payment_methods auth/link because of ", e)
+ JSON.Encode.null->resolve
+ })
+}
+
+let callAuthExchange = (
+ ~publicToken,
+ ~clientSecret,
+ ~paymentMethodType,
+ ~publishableKey,
+ ~setOptionValue: (PaymentType.options => PaymentType.options) => unit,
+) => {
+ open Promise
+ open PaymentType
+ let endpoint = ApiEndpoint.getApiEndPoint()
+ let logger = OrcaLogger.make(~source=Elements(Payment), ())
+ let uri = `${endpoint}/payment_methods/auth/exchange`
+ let updatedBody = [
+ ("client_secret", clientSecret->Option.getOr("")->JSON.Encode.string),
+ ("payment_id", clientSecret->Option.getOr("")->getPaymentId->JSON.Encode.string),
+ ("payment_method", "bank_debit"->JSON.Encode.string),
+ ("payment_method_type", paymentMethodType->JSON.Encode.string),
+ ("public_token", publicToken->JSON.Encode.string),
+ ]
+
+ let headers = [("Content-Type", "application/json"), ("api-key", publishableKey)]->Dict.fromArray
+
+ fetchApi(
+ uri,
+ ~method=#POST,
+ ~bodyStr=updatedBody->getJsonFromArrayOfJson->JSON.stringify,
+ ~headers,
+ (),
+ )
+ ->then(res => {
+ let statusCode = res->Fetch.Response.status->Int.toString
+ if statusCode->String.charAt(0) !== "2" {
+ res
+ ->Fetch.Response.json
+ ->then(_ => {
+ JSON.Encode.null->resolve
+ })
+ } else {
+ fetchCustomerPaymentMethodList(
+ ~clientSecret=clientSecret->Option.getOr(""),
+ ~publishableKey,
+ ~optLogger=Some(logger),
+ ~switchToCustomPod=false,
+ ~endpoint,
+ )
+ ->then(customerListResponse => {
+ let customerListResponse =
+ [("customerPaymentMethods", customerListResponse)]->Dict.fromArray
+ setOptionValue(
+ prev => {
+ ...prev,
+ customerPaymentMethods: createCustomerObjArr(customerListResponse),
+ },
+ )
+ JSON.Encode.null->resolve
+ })
+ ->catch(e => {
+ Console.log2(
+ "Unable to retrieve customer/payment_methods after auth/exchange because of ",
+ e,
+ )
+ JSON.Encode.null->resolve
+ })
+ }
+ })
+ ->catch(e => {
+ Console.log2("Unable to retrieve payment_methods auth/exchange because of ", e)
+ JSON.Encode.null->resolve
+ })
+}
diff --git a/src/Utilities/PmAuthConnectorUtils.res b/src/Utilities/PmAuthConnectorUtils.res
new file mode 100644
index 000000000..d1c8621da
--- /dev/null
+++ b/src/Utilities/PmAuthConnectorUtils.res
@@ -0,0 +1,85 @@
+type pmAuthConnector = PLAID | NONE
+type isPmAuthConnectorReady = {plaid: bool}
+let pmAuthNameToTypeMapper = authConnectorName => {
+ switch authConnectorName {
+ | "plaid" => PLAID
+ | _ => NONE
+ }
+}
+
+let pmAuthConnectorToScriptUrlMapper = authConnector => {
+ switch authConnector {
+ | PLAID => "https://cdn.plaid.com/link/v2/stable/link-initialize.js"
+ | NONE => ""
+ }
+}
+
+let mountAuthConnectorScript = (
+ ~authConnector,
+ ~onScriptLoaded,
+ ~logger: OrcaLogger.loggerMake,
+) => {
+ let authConnector = authConnector->Option.getOr("")
+ let pmAuthConnectorScriptUrl =
+ authConnector->pmAuthNameToTypeMapper->pmAuthConnectorToScriptUrlMapper
+ let pmAuthConnectorScript = Window.createElement("script")
+ logger.setLogInfo(
+ ~value=`Pm Auth Connector ${authConnector} Script Loading`,
+ ~eventName=PM_AUTH_CONNECTOR_SCRIPT,
+ (),
+ )
+ pmAuthConnectorScript->Window.elementSrc(pmAuthConnectorScriptUrl)
+ pmAuthConnectorScript->Window.elementOnerror(_ => {
+ logger.setLogInfo(
+ ~value=`Pm Auth Connector ${authConnector} Script Load Failure`,
+ ~eventName=PM_AUTH_CONNECTOR_SCRIPT,
+ (),
+ )
+ })
+ pmAuthConnectorScript->Window.elementOnload(_ => {
+ onScriptLoaded(authConnector)
+ logger.setLogInfo(
+ ~value=`Pm Auth Connector ${authConnector} Script Loaded`,
+ ~eventName=PM_AUTH_CONNECTOR_SCRIPT,
+ (),
+ )
+ })
+ Window.body->Window.appendChild(pmAuthConnectorScript)
+}
+
+let mountAllRequriedAuthConnectorScripts = (
+ ~pmAuthConnectorsArr,
+ ~onScriptLoaded,
+ ~logger: OrcaLogger.loggerMake,
+) => {
+ pmAuthConnectorsArr->Array.forEach(item => {
+ mountAuthConnectorScript(~authConnector=item, ~onScriptLoaded, ~logger)
+ })
+}
+
+let findPmAuthAllPMAuthConnectors = (
+ paymentMethodListValue: array,
+) => {
+ let bankDebitPaymentMethodsArr =
+ paymentMethodListValue->Array.filter(item => item.payment_method == "bank_debit")
+
+ let pmAuthConnectorDict = Dict.make()
+
+ bankDebitPaymentMethodsArr->Array.forEach(item => {
+ item.payment_method_types->Array.forEach(item => {
+ if item.pm_auth_connector->Option.isSome {
+ pmAuthConnectorDict->Dict.set(item.payment_method_type, item.pm_auth_connector)
+ }
+ })
+ })
+
+ pmAuthConnectorDict
+}
+
+let getAllRequiredPmAuthConnectors = pmAuthConnectorsDict => {
+ let requiredPmAuthConnectorsArr = pmAuthConnectorsDict->Dict.valuesToArray
+
+ requiredPmAuthConnectorsArr->Array.filterWithIndex((item, idx) =>
+ idx == requiredPmAuthConnectorsArr->Array.indexOf(item)
+ )
+}
diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res
index 1164f404d..c3e79a6c2 100644
--- a/src/Utilities/Utils.res
+++ b/src/Utilities/Utils.res
@@ -1336,3 +1336,6 @@ let handleFailureResponse = (~message, ~errorType) =>
]->getJsonFromArrayOfJson,
),
]->getJsonFromArrayOfJson
+
+let getPaymentId = clientSecret =>
+ String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("")
diff --git a/src/libraries/Plaid.res b/src/libraries/Plaid.res
new file mode 100644
index 000000000..ff8b7165e
--- /dev/null
+++ b/src/libraries/Plaid.res
@@ -0,0 +1,22 @@
+// * For Documentation - https://plaid.com/docs/link/web/
+
+type createArgs = {
+ token: string,
+ onSuccess: (string, JSON.t) => unit,
+ onLoad?: unit => unit,
+ onExit?: JSON.t => unit,
+ onEvent?: JSON.t => unit,
+}
+
+type createReturn = {
+ @as("open") open_: unit => unit,
+ exit: unit => unit,
+ destroy: unit => unit,
+ submit: unit => unit,
+}
+
+@val @scope(("window", "Plaid"))
+external create: createArgs => createReturn = "create"
+
+@val @scope(("window", "Plaid"))
+external version: string = "version"
diff --git a/src/orca-loader/Elements.res b/src/orca-loader/Elements.res
index 9cc489a13..261075ea0 100644
--- a/src/orca-loader/Elements.res
+++ b/src/orca-loader/Elements.res
@@ -114,12 +114,27 @@ let make = (
)
})
+ let onPlaidCallback = mountedIframeRef => {
+ (ev: Types.event) => {
+ let json = ev.data->Identity.anyTypeToJson
+ let dict = json->getDictFromJson
+ let isPlaidExist = dict->getBool("isPlaid", false)
+ if isPlaidExist {
+ mountedIframeRef->Window.iframePostMessage(
+ [("isPlaid", true->JSON.Encode.bool), ("data", json)]->Dict.fromArray,
+ )
+ }
+ }
+ }
+
let fetchPaymentsList = (mountedIframeRef, componentType) => {
let handlePaymentMethodsLoaded = (event: Types.event) => {
let json = event.data->Identity.anyTypeToJson
let dict = json->getDictFromJson
let isPaymentMethodsData = dict->getString("data", "") === "payment_methods"
if isPaymentMethodsData {
+ addSmartEventListener("message", onPlaidCallback(mountedIframeRef), "onPlaidCallback")
+
let json = dict->getJsonFromDict("response", JSON.Encode.null)
let isApplePayPresent = PaymentMethodsRecord.getPaymentMethodTypeFromList(
~paymentMethodListValue=json
diff --git a/src/orca-loader/Hyper.res b/src/orca-loader/Hyper.res
index 8379fa373..8fff0138a 100644
--- a/src/orca-loader/Hyper.res
+++ b/src/orca-loader/Hyper.res
@@ -216,7 +216,7 @@ let make = (publishableKey, options: option, analyticsInfo: optionArray.get(0)->Option.getOr("")
+ let paymentIntentID = clientSecret->getPaymentId
let retrievePaymentUrl = `${endpoint}/payments/${paymentIntentID}?client_secret=${clientSecret}`
open Promise
logApi(
diff --git a/src/orca-log-catcher/OrcaLogger.res b/src/orca-log-catcher/OrcaLogger.res
index 3f222ca17..7242fae97 100644
--- a/src/orca-log-catcher/OrcaLogger.res
+++ b/src/orca-log-catcher/OrcaLogger.res
@@ -27,6 +27,7 @@ type eventName =
| CREATE_CUSTOMER_PAYMENT_METHODS_CALL_INIT
| CREATE_CUSTOMER_PAYMENT_METHODS_CALL
| TRUSTPAY_SCRIPT
+ | PM_AUTH_CONNECTOR_SCRIPT
| GOOGLE_PAY_SCRIPT
| APPLE_PAY_FLOW
| GOOGLE_PAY_FLOW
@@ -98,6 +99,7 @@ let eventNameToStrMapper = eventName => {
| CREATE_CUSTOMER_PAYMENT_METHODS_CALL_INIT => "CREATE_CUSTOMER_PAYMENT_METHODS_CALL_INIT"
| CREATE_CUSTOMER_PAYMENT_METHODS_CALL => "CREATE_CUSTOMER_PAYMENT_METHODS_CALL"
| TRUSTPAY_SCRIPT => "TRUSTPAY_SCRIPT"
+ | PM_AUTH_CONNECTOR_SCRIPT => "PM_AUTH_CONNECTOR_SCRIPT"
| GOOGLE_PAY_SCRIPT => "GOOGLE_PAY_SCRIPT"
| APPLE_PAY_FLOW => "APPLE_PAY_FLOW"
| GOOGLE_PAY_FLOW => "GOOGLE_PAY_FLOW"
@@ -568,6 +570,8 @@ let make = (~sessionId=?, ~source: source, ~clientSecret=?, ~merchantId=?, ~meta
DISPLAY_QR_CODE_INFO_PAGE,
DISPLAY_VOUCHER,
LOADER_CHANGED,
+ PAYMENT_METHODS_CALL,
+ PAYMENT_METHOD_CHANGED,
SESSIONS_CALL,
RETRIEVE_CALL,
DISPLAY_THREE_DS_SDK,