From ceab1614e80d8cfb96ac3eea04486ebd509e0770 Mon Sep 17 00:00:00 2001 From: Vrishab Srivatsa <136090360+vsrivatsa-juspay@users.noreply.github.com> Date: Thu, 4 Apr 2024 12:58:53 +0530 Subject: [PATCH 1/5] feat(3ds): three DS SDK - adding logs to track milestone events (#265) Co-authored-by: Pritish Budhiraja <1805317@kiit.ac.in> --- src/ThreeDSAuth.res | 27 ++++- src/ThreeDSMethod.res | 52 +++++++--- src/Utilities/LoggerUtils.res | 18 +--- src/Utilities/PaymentHelpers.res | 154 ++++++++++++++++++++++------ src/orca-loader/Elements.res | 7 +- src/orca-loader/Hyper.res | 10 +- src/orca-log-catcher/OrcaLogger.res | 33 ++++-- 7 files changed, 224 insertions(+), 77 deletions(-) diff --git a/src/ThreeDSAuth.res b/src/ThreeDSAuth.res index 3f00fe92e..6fa130721 100644 --- a/src/ThreeDSAuth.res +++ b/src/ThreeDSAuth.res @@ -5,7 +5,7 @@ let make = () => { let (openModal, setOpenModal) = React.useState(_ => false) let (loader, setloader) = React.useState(_ => true) - let logger = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom) + let logger = OrcaLogger.make() React.useEffect0(() => { handlePostMessage([("iframeMountedCallback", true->JSON.Encode.bool)]) @@ -16,6 +16,9 @@ let make = () => { let metadata = dict->getJsonObjectFromDict("metadata") let metaDataDict = metadata->JSON.Decode.object->Option.getOr(Dict.make()) let paymentIntentId = metaDataDict->getString("paymentIntentId", "") + let publishableKey = metaDataDict->getString("publishableKey", "") + logger.setClientSecret(paymentIntentId) + logger.setMerchantId(publishableKey) let headersDict = metaDataDict ->getJsonObjectFromDict("headers") @@ -51,6 +54,14 @@ let make = () => { let ele = Window.querySelector("#threeDsAuthDiv") + LoggerUtils.handleLogging( + ~optLogger=Some(logger), + ~eventName=DISPLAY_THREE_DS_SDK, + ~value=transStatus, + ~paymentMethod="CARD", + (), + ) + switch ele->Nullable.toOption { | Some(elem) => if transStatus === "C" { @@ -63,13 +74,25 @@ let make = () => { form.appendChild(input) form.submit() } else { - let form1 = elem->OrcaUtils.makeForm(threeDsAuthoriseUrl, "3dsFrintionLess") + let form1 = elem->OrcaUtils.makeForm(threeDsAuthoriseUrl, "3dsFrictionLess") form1.submit() } | None => () } resolve(json) }) + ->catch(err => { + let exceptionMessage = err->Utils.formatException + LoggerUtils.handleLogging( + ~optLogger=Some(logger), + ~eventName=DISPLAY_THREE_DS_SDK, + ~value=exceptionMessage->JSON.stringify, + ~paymentMethod="CARD", + ~logType=ERROR, + (), + ) + JSON.Encode.null->resolve + }) ->ignore } } diff --git a/src/ThreeDSMethod.res b/src/ThreeDSMethod.res index 7255e39af..de218ada5 100644 --- a/src/ThreeDSMethod.res +++ b/src/ThreeDSMethod.res @@ -1,7 +1,7 @@ open Utils @react.component let make = () => { - let logger = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom) + let logger = OrcaLogger.make() let mountToInnerHTML = innerHTML => { let ele = Window.querySelector("#threeDsInvisibleIframe") @@ -40,25 +40,39 @@ let make = () => { ->Belt.Option.flatMap(JSON.Decode.object) ->Belt.Option.flatMap(x => x->Dict.get("three_ds_method_data")) ->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 => { - mountToInnerHTML(res) - resolve(res) - }) - ->then(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) + 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(e => { + ->catch(err => { + let exceptionMessage = err->Utils.formatException metadata->Utils.getDictFromJson->Dict.set("3dsMethodComp", "N"->JSON.Encode.string) handlePostMessage([ ("fullscreen", true->JSON.Encode.bool), @@ -66,7 +80,15 @@ let make = () => { ("iframeId", iframeId->JSON.Encode.string), ("metadata", metadata), ]) - reject(e) + LoggerUtils.handleLogging( + ~optLogger=Some(logger), + ~eventName=THREE_DS_METHOD_RESULT, + ~value=exceptionMessage->JSON.stringify, + ~paymentMethod="CARD", + ~logType=ERROR, + (), + ) + reject(err) }) ->ignore diff --git a/src/Utilities/LoggerUtils.res b/src/Utilities/LoggerUtils.res index 36511b548..3e7c0737c 100644 --- a/src/Utilities/LoggerUtils.res +++ b/src/Utilities/LoggerUtils.res @@ -1,19 +1,8 @@ -type logType = Request | Response | NoResponse | Method | Err -let getLogtype = val => { - switch val { - | "request" => Request - | "response" => Response - | "no_response" => NoResponse - | "method" => Method - | "err" => Err - | _ => Err - } -} let logApi = ( ~eventName, ~statusCode="", ~data: JSON.t=Dict.make()->JSON.Encode.object, - ~type_, + ~apiLogType: OrcaLogger.apiLogType, ~url="", ~paymentMethod="", ~result: JSON.t=Dict.make()->JSON.Encode.object, @@ -22,8 +11,7 @@ let logApi = ( ~logCategory: OrcaLogger.logCategory=API, (), ) => { - let logtype = getLogtype(type_) - let (value, internalMetadata) = switch logtype { + let (value, internalMetadata) = switch apiLogType { | Request => ([("url", url->JSON.Encode.string)], []) | Response => ( [("url", url->JSON.Encode.string), ("statusCode", statusCode->JSON.Encode.string)], @@ -55,7 +43,7 @@ let logApi = ( ~internalMetadata=ArrayType(internalMetadata), ~logType, ~logCategory, - ~type_, + ~apiLogType, (), ) | None => () diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index 486e716c5..fa16ef0fe 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -21,7 +21,7 @@ let retrievePaymentIntent = (clientSecret, headers, ~optLogger, ~switchToCustomP logApi( ~optLogger, ~url=uri, - ~type_="request", + ~apiLogType=Request, ~eventName=RETRIEVE_CALL_INIT, ~logType=INFO, ~logCategory=API, @@ -44,7 +44,7 @@ let retrievePaymentIntent = (clientSecret, headers, ~optLogger, ~switchToCustomP ~url=uri, ~data, ~statusCode, - ~type_="err", + ~apiLogType=Err, ~eventName=RETRIEVE_CALL, ~logType=ERROR, ~logCategory=API, @@ -57,7 +57,7 @@ let retrievePaymentIntent = (clientSecret, headers, ~optLogger, ~switchToCustomP ~optLogger, ~url=uri, ~statusCode, - ~type_="response", + ~apiLogType=Response, ~eventName=RETRIEVE_CALL, ~logType=INFO, ~logCategory=API, @@ -77,8 +77,8 @@ let threeDsMethod = (url, threeDsMethodData, ~optLogger) => { logApi( ~optLogger, ~url, - ~type_="request", - ~eventName=RETRIEVE_CALL_INIT, + ~apiLogType=Request, + ~eventName=THREE_DS_METHOD_CALL_INIT, ~logType=INFO, ~logCategory=API, (), @@ -88,11 +88,50 @@ let threeDsMethod = (url, threeDsMethodData, ~optLogger) => { fetchApiWithNoCors(url, ~method=#POST, ~bodyStr=body, ()) ->then(res => { - res->Fetch.Response.text + 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(e => { - Console.log2("Unable to call 3ds method ", e) - reject(e) + ->catch(err => { + let exceptionMessage = err->Utils.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) }) } @@ -115,17 +154,58 @@ let threeDsAuth = (~clientSecret, ~optLogger, ~threeDsMethodComp, ~headers) => { logApi( ~optLogger, ~url, - ~type_="request", - ~eventName=RETRIEVE_CALL_INIT, + ~apiLogType=Request, + ~eventName=AUTHENTICATION_CALL_INIT, ~logType=INFO, ~logCategory=API, (), ) fetchApi(url, ~method=#POST, ~bodyStr=body->JSON.stringify, ~headers=headers->Dict.fromArray, ()) - ->then(res => res->Fetch.Response.json) - ->catch(e => { - Console.log2("Unable to call 3ds auth ", e) - reject(e) + ->then(res => { + let statusCode = res->Fetch.Response.status->Int.toString + if statusCode->String.charAt(0) !== "2" { + res + ->Fetch.Response.json + ->then(data => { + logApi( + ~optLogger, + ~url, + ~data, + ~statusCode, + ~apiLogType=Err, + ~eventName=AUTHENTICATION_CALL, + ~logType=ERROR, + ~logCategory=API, + (), + ) + JSON.Encode.null->resolve + }) + } else { + logApi( + ~optLogger, + ~url, + ~statusCode, + ~apiLogType=Response, + ~eventName=AUTHENTICATION_CALL, + (), + ) + res->Fetch.Response.json + } + }) + ->catch(err => { + let exceptionMessage = err->Utils.formatException + Console.log2("Unable to call 3ds auth ", exceptionMessage) + logApi( + ~optLogger, + ~url, + ~eventName=AUTHENTICATION_CALL, + ~apiLogType=NoResponse, + ~data=exceptionMessage, + ~logType=ERROR, + ~logCategory=API, + (), + ) + reject(err) }) } @@ -184,7 +264,7 @@ let rec intentCall = ( logApi( ~optLogger, ~url=uri, - ~type_="request", + ~apiLogType=Request, ~eventName=initEventName, ~logType=INFO, ~logCategory=API, @@ -238,7 +318,7 @@ let rec intentCall = ( ~url=uri, ~data, ~statusCode, - ~type_="err", + ~apiLogType=Err, ~eventName, ~logType=ERROR, ~logCategory=API, @@ -274,7 +354,7 @@ let rec intentCall = ( ~optLogger, ~url=uri, ~statusCode, - ~type_="no_response", + ~apiLogType=NoResponse, ~data=exceptionMessage, ~eventName, ~logType=ERROR, @@ -338,7 +418,7 @@ let rec intentCall = ( ->then(data => { Promise.make( (resolve, _) => { - logApi(~optLogger, ~url=uri, ~statusCode, ~type_="response", ~eventName, ()) + logApi(~optLogger, ~url=uri, ~statusCode, ~apiLogType=Response, ~eventName, ()) let intent = PaymentConfirmTypes.itemToObjMapper(data->getDictFromJson) let paymentMethod = switch paymentType { | Card => "CARD" @@ -416,6 +496,7 @@ let rec intentCall = ( [ ("qrData", qrData->JSON.Encode.string), ("paymentIntentId", clientSecret->JSON.Encode.string), + ("publishableKey", confirmParam.publishableKey->JSON.Encode.string), ("headers", headerObj->JSON.Encode.object), ("expiryTime", expiryTime->Belt.Float.toString->JSON.Encode.string), ("url", url.href->JSON.Encode.string), @@ -462,11 +543,20 @@ let rec intentCall = ( [ ("threeDSData", threeDsData->JSON.Encode.object), ("paymentIntentId", clientSecret->JSON.Encode.string), + ("publishableKey", confirmParam.publishableKey->JSON.Encode.string), ("headers", headerObj->JSON.Encode.object), ("url", url.href->JSON.Encode.string), ("iframeId", iframeId->JSON.Encode.string), ]->Dict.fromArray + handleLogging( + ~optLogger, + ~value=do3dsMethodCall ? "Y" : "N", + ~eventName=THREE_DS_METHOD, + ~paymentMethod, + (), + ) + if do3dsMethodCall { handlePostMessage([ ("fullscreen", true->JSON.Encode.bool), @@ -600,7 +690,7 @@ let rec intentCall = ( ~optLogger, ~url=uri, ~eventName, - ~type_="no_response", + ~apiLogType=NoResponse, ~data=exceptionMessage, ~logType=ERROR, ~logCategory=API, @@ -911,7 +1001,7 @@ let fetchSessions = ( logApi( ~optLogger, ~url=uri, - ~type_="request", + ~apiLogType=Request, ~eventName=SESSIONS_CALL_INIT, ~logType=INFO, ~logCategory=API, @@ -935,7 +1025,7 @@ let fetchSessions = ( ~url=uri, ~data, ~statusCode, - ~type_="err", + ~apiLogType=Err, ~eventName=SESSIONS_CALL, ~logType=ERROR, ~logCategory=API, @@ -948,7 +1038,7 @@ let fetchSessions = ( ~optLogger, ~url=uri, ~statusCode, - ~type_="response", + ~apiLogType=Response, ~eventName=SESSIONS_CALL, ~logType=INFO, ~logCategory=API, @@ -962,7 +1052,7 @@ let fetchSessions = ( logApi( ~optLogger, ~url=uri, - ~type_="no_response", + ~apiLogType=NoResponse, ~eventName=SESSIONS_CALL, ~logType=ERROR, ~logCategory=API, @@ -986,7 +1076,7 @@ let fetchPaymentMethodList = ( logApi( ~optLogger=Some(logger), ~url=uri, - ~type_="request", + ~apiLogType=Request, ~eventName=PAYMENT_METHODS_CALL_INIT, ~logType=INFO, ~logCategory=API, @@ -1009,7 +1099,7 @@ let fetchPaymentMethodList = ( ~url=uri, ~data, ~statusCode, - ~type_="err", + ~apiLogType=Err, ~eventName=PAYMENT_METHODS_CALL, ~logType=ERROR, ~logCategory=API, @@ -1022,7 +1112,7 @@ let fetchPaymentMethodList = ( ~optLogger=Some(logger), ~url=uri, ~statusCode, - ~type_="response", + ~apiLogType=Response, ~eventName=PAYMENT_METHODS_CALL, ~logType=INFO, ~logCategory=API, @@ -1036,7 +1126,7 @@ let fetchPaymentMethodList = ( logApi( ~optLogger=Some(logger), ~url=uri, - ~type_="no_response", + ~apiLogType=NoResponse, ~eventName=PAYMENT_METHODS_CALL, ~logType=ERROR, ~logCategory=API, @@ -1060,7 +1150,7 @@ let fetchCustomerDetails = ( logApi( ~optLogger, ~url=uri, - ~type_="request", + ~apiLogType=Request, ~eventName=CUSTOMER_PAYMENT_METHODS_CALL_INIT, ~logType=INFO, ~logCategory=API, @@ -1083,7 +1173,7 @@ let fetchCustomerDetails = ( ~url=uri, ~data, ~statusCode, - ~type_="err", + ~apiLogType=Err, ~eventName=CUSTOMER_PAYMENT_METHODS_CALL, ~logType=ERROR, ~logCategory=API, @@ -1096,7 +1186,7 @@ let fetchCustomerDetails = ( ~optLogger, ~url=uri, ~statusCode, - ~type_="response", + ~apiLogType=Response, ~eventName=CUSTOMER_PAYMENT_METHODS_CALL, ~logType=INFO, ~logCategory=API, @@ -1110,7 +1200,7 @@ let fetchCustomerDetails = ( logApi( ~optLogger, ~url=uri, - ~type_="no_response", + ~apiLogType=NoResponse, ~eventName=CUSTOMER_PAYMENT_METHODS_CALL, ~logType=ERROR, ~logCategory=API, diff --git a/src/orca-loader/Elements.res b/src/orca-loader/Elements.res index 592bca90f..118fb1689 100644 --- a/src/orca-loader/Elements.res +++ b/src/orca-loader/Elements.res @@ -129,7 +129,12 @@ let make = ( let msg = [("paymentMethodList", json)]->Dict.fromArray mountedIframeRef->Window.iframePostMessage(msg) let maskedPayload = json->PaymentHelpers.maskPayload->JSON.stringify - logger.setLogInfo(~value=maskedPayload, ~eventName=PAYMENT_METHODS_RESPONSE, ()) + logger.setLogInfo( + ~value="", + ~internalMetadata=maskedPayload, + ~eventName=PAYMENT_METHODS_RESPONSE, + (), + ) // }, 5000)->ignore json->resolve }) diff --git a/src/orca-loader/Hyper.res b/src/orca-loader/Hyper.res index 0ab0a3773..8fc2fa041 100644 --- a/src/orca-loader/Hyper.res +++ b/src/orca-loader/Hyper.res @@ -208,7 +208,7 @@ let make = (publishableKey, options: option, analyticsInfo: option, analyticsInfo: option, analyticsInfo: option, analyticsInfo: optionDict.get("submitSuccessful") { | Some(val) => logApi( - ~type_="method", + ~apiLogType=Method, ~optLogger=Some(logger), ~result=val, ~paymentMethod="confirmPayment", @@ -436,7 +436,7 @@ let make = (publishableKey, options: option, analyticsInfo: optionDict.get("submitSuccessful") { | Some(val) => logApi( - ~type_="method", + ~apiLogType=Method, ~optLogger=Some(logger), ~result=val, ~paymentMethod="confirmCardPayment", diff --git a/src/orca-log-catcher/OrcaLogger.res b/src/orca-log-catcher/OrcaLogger.res index b97a1829c..3032c428e 100644 --- a/src/orca-log-catcher/OrcaLogger.res +++ b/src/orca-log-catcher/OrcaLogger.res @@ -1,3 +1,4 @@ +type apiLogType = Request | Response | NoResponse | Method | Err type logType = DEBUG | INFO | ERROR | WARNING | SILENT type logCategory = API | USER_ERROR | USER_EVENT | MERCHANT_EVENT @@ -11,6 +12,10 @@ type eventName = | INPUT_FIELD_CHANGED | RETRIEVE_CALL_INIT | RETRIEVE_CALL + | AUTHENTICATION_CALL_INIT + | AUTHENTICATION_CALL + | THREE_DS_METHOD_CALL_INIT + | THREE_DS_METHOD_CALL | CONFIRM_CALL_INIT | CONFIRM_CALL | SESSIONS_CALL_INIT @@ -54,6 +59,9 @@ type eventName = | DISPLAY_BANK_TRANSFER_INFO_PAGE | DISPLAY_QR_CODE_INFO_PAGE | DISPLAY_VOUCHER + | DISPLAY_THREE_DS_SDK + | THREE_DS_METHOD + | THREE_DS_METHOD_RESULT | PAYMENT_METHODS_RESPONSE | LOADER_CHANGED | PAYMENT_SESSION_INITIATED @@ -69,6 +77,10 @@ let eventNameToStrMapper = eventName => { | INPUT_FIELD_CHANGED => "INPUT_FIELD_CHANGED" | RETRIEVE_CALL_INIT => "RETRIEVE_CALL_INIT" | 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" @@ -112,6 +124,9 @@ let eventNameToStrMapper = eventName => { | DISPLAY_BANK_TRANSFER_INFO_PAGE => "DISPLAY_BANK_TRANSFER_INFO_PAGE" | DISPLAY_QR_CODE_INFO_PAGE => "DISPLAY_QR_CODE_INFO_PAGE" | DISPLAY_VOUCHER => "DISPLAY_VOUCHER" + | DISPLAY_THREE_DS_SDK => "DISPLAY_THREE_DS_SDK" + | THREE_DS_METHOD => "THREE_DS_METHOD" + | THREE_DS_METHOD_RESULT => "THREE_DS_METHOD_RESULT" | PAYMENT_METHODS_RESPONSE => "PAYMENT_METHODS_RESPONSE" | LOADER_CHANGED => "LOADER_CHANGED" | PAYMENT_SESSION_INITIATED => "PAYMENT_SESSION_INITIATED" @@ -178,7 +193,7 @@ type loggerMake = { ~logType: logType=?, ~logCategory: logCategory=?, ~paymentMethod: string=?, - ~type_: string=?, + ~apiLogType: apiLogType=?, unit, ) => unit, setLogInitiated: unit => unit, @@ -213,7 +228,7 @@ let defaultLoggerConfig = { ~logType as _=?, ~logCategory as _=?, ~paymentMethod as _=?, - ~type_ as _=?, + ~apiLogType as _=?, (), ) => (), setLogInfo: ( @@ -500,6 +515,8 @@ let make = ( PAYMENT_DATA_FILLED, PAYMENT_ATTEMPT, CONFIRM_CALL, + AUTHENTICATION_CALL, + THREE_DS_METHOD_CALL, SDK_CRASH, REDIRECTING_USER, DISPLAY_BANK_TRANSFER_INFO_PAGE, @@ -529,7 +546,7 @@ let make = ( } } - let calculateLatencyHook = (~eventName, ~type_="", ()) => { + let calculateLatencyHook = (~eventName, ~apiLogType=Method, ()) => { let currentTimestamp = Date.now() let latency = switch eventName { | PAYMENT_ATTEMPT => { @@ -539,6 +556,8 @@ let make = ( | _ => -1. } } + | AUTHENTICATION_CALL + | THREE_DS_METHOD_CALL | RETRIEVE_CALL | CONFIRM_CALL | SESSIONS_CALL @@ -546,8 +565,8 @@ let make = ( | CUSTOMER_PAYMENT_METHODS_CALL => { let logRequestTimestamp = events.contents->Dict.get(eventName->eventNameToStrMapper ++ "_INIT") - switch (logRequestTimestamp, type_) { - | (Some(_), "request") => 0. + switch (logRequestTimestamp, apiLogType) { + | (Some(_), Request) => 0. | (Some(float), _) => currentTimestamp -. float | _ => 0. } @@ -618,12 +637,12 @@ let make = ( ~logType=INFO, ~logCategory=API, ~paymentMethod="", - ~type_="", + ~apiLogType=Request, (), ) => { let eventNameStr = eventName->eventNameToStrMapper let firstEvent = events.contents->Dict.get(eventNameStr)->Option.isNone - let latency = calculateLatencyHook(~eventName, ~type_, ()) + let latency = calculateLatencyHook(~eventName, ~apiLogType, ()) let localTimestamp = timestamp->Option.getOr(Date.now()->Belt.Float.toString) let localTimestampFloat = localTimestamp->Belt.Float.fromString->Option.getOr(Date.now()) { From ad2fa630c639c7b246176f1d2683050a58ad3e36 Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja <1805317@kiit.ac.in> Date: Thu, 4 Apr 2024 13:00:30 +0530 Subject: [PATCH 2/5] feat: giropay dynamic fields added (#267) --- src/Components/DynamicFields.res | 824 ++++++++++++------------- src/Payments/PaymentMethodsRecord.res | 3 +- src/Payments/PaymentMethodsWrapper.res | 2 +- 3 files changed, 413 insertions(+), 416 deletions(-) diff --git a/src/Components/DynamicFields.res b/src/Components/DynamicFields.res index 1784479e3..bef9f90ae 100644 --- a/src/Components/DynamicFields.res +++ b/src/Components/DynamicFields.res @@ -318,425 +318,421 @@ let make = ( dynamicFieldsToRenderInsideBilling->Array.length > 0 && (dynamicFieldsToRenderInsideBilling->Array.length > 1 || !isOnlyInfoElementPresent) - { - fieldsArr->Array.length > 0 - ? <> - {dynamicFieldsToRenderOutsideBilling - ->Array.mapWithIndex((item, index) => { -
Int.toString}`} - className="flex flex-col w-full place-content-between" - style={ReactDOMStyle.make( - ~marginTop=index !== 0 || paymentMethod === "card" - ? themeObj.spacingGridColumn - : "", - ~gridColumnGap=themeObj.spacingGridRow, - (), - )}> - {switch item { - | CardNumber => - - | CardExpiryMonth - | CardExpiryYear - | CardExpiryMonthAndYear => - - | CardCvc => - - | CardExpiryAndCvc => -
- Array.length > 0}> + {<> + {dynamicFieldsToRenderOutsideBilling + ->Array.mapWithIndex((item, index) => { +
Int.toString}`} + className="flex flex-col w-full place-content-between" + style={ReactDOMStyle.make( + ~marginTop=index !== 0 || paymentMethod === "card" ? themeObj.spacingGridColumn : "", + ~gridColumnGap=themeObj.spacingGridRow, + (), + )}> + {switch item { + | CardNumber => + + | CardExpiryMonth + | CardExpiryYear + | CardExpiryMonthAndYear => + + | CardCvc => + + | CardExpiryAndCvc => +
+ + +
+ | Currency(currencyArr) => + + | FullName => + getCustomFieldName} + optionalRequiredFields={Some(requiredFields)} + /> + | Email + | InfoElement + | Country + | Bank + | None + | BillingName + | PhoneNumber + | AddressLine1 + | AddressLine2 + | AddressCity + | StateAndCity + | AddressPincode + | AddressState + | BlikCode + | SpecialField(_) + | CountryAndPincode(_) + | AddressCountry(_) => React.null + }} +
+ }) + ->React.array} + +
+ {React.string(localeString.billingDetailsText)} +
+ {dynamicFieldsToRenderInsideBilling + ->Array.mapWithIndex((item, index) => { +
Int.toString}`} + className="flex flex-col w-full place-content-between"> + {switch item { + | BillingName => + | Email => + | PhoneNumber => + | StateAndCity => +
+ { + let value = ReactEvent.Form.target(ev)["value"] + setCity(prev => { + isValid: value !== "" ? Some(true) : Some(false), + value, + errorString: value !== "" ? "" : prev.errorString, + }) + }} + onBlur={ev => { + let value = ReactEvent.Focus.target(ev)["value"] + setCity(prev => { + ...prev, + isValid: Some(value !== ""), + }) + }} + paymentType + type_="text" + name="city" + inputRef=cityRef + placeholder=localeString.cityLabel + /> + {switch stateJson { + | Some(options) => + Utils.getStateNames({ + value: country, + isValid: None, + errorString: "", + })} + /> + | None => React.null + }} +
+ | CountryAndPincode(countryArr) => +
+ + { + let value = ReactEvent.Focus.target(ev)["value"] + setPostalCode(prev => { + ...prev, + isValid: Some(value !== ""), + }) + }} + onChange=onPostalChange + paymentType + name="postal" + inputRef=postalRef + placeholder=localeString.postalCodeLabel + /> +
+ | AddressLine1 => + { + let value = ReactEvent.Form.target(ev)["value"] + setLine1(prev => { + isValid: value !== "" ? Some(true) : Some(false), + value, + errorString: value !== "" ? "" : prev.errorString, + }) + }} + onBlur={ev => { + let value = ReactEvent.Focus.target(ev)["value"] + setLine1(prev => { + ...prev, + isValid: Some(value !== ""), + }) + }} paymentType - type_="tel" - appearance=config.appearance - maxLength=7 - inputRef=expiryRef - placeholder="MM / YY" + type_="text" + name="line1" + inputRef=line1Ref + placeholder=localeString.line1Placeholder + /> + | AddressLine2 => + { + let value = ReactEvent.Form.target(ev)["value"] + setLine2(prev => { + isValid: value !== "" ? Some(true) : Some(false), + value, + errorString: value !== "" ? "" : prev.errorString, + }) + }} + onBlur={ev => { + let value = ReactEvent.Focus.target(ev)["value"] + setLine2(prev => { + ...prev, + isValid: Some(value !== ""), + }) + }} + paymentType + type_="text" + name="line2" + inputRef=line2Ref + placeholder=localeString.line2Placeholder + /> + | AddressCity => + { + let value = ReactEvent.Form.target(ev)["value"] + setCity(prev => { + isValid: value !== "" ? Some(true) : Some(false), + value, + errorString: value !== "" ? "" : prev.errorString, + }) + }} + onBlur={ev => { + let value = ReactEvent.Focus.target(ev)["value"] + setCity(prev => { + ...prev, + isValid: Some(value !== ""), + }) + }} + paymentType + type_="text" + name="city" + inputRef=cityRef + placeholder=localeString.cityLabel /> - + switch stateJson { + | Some(options) => + Utils.getStateNames({ + value: country, + isValid: None, + errorString: "", + })} + /> + | None => React.null + } + | AddressPincode => + { + let value = ReactEvent.Focus.target(ev)["value"] + setPostalCode(prev => { + ...prev, + isValid: Some(value !== ""), + }) + }} + onChange=onPostalChange paymentType - rightIcon={CardUtils.setRightIconForCvc( - ~cardEmpty, - ~cardInvalid, - ~color=themeObj.colorIconCardCvcError, - ~cardComplete, - )} + name="postal" + inputRef=postalRef + placeholder=localeString.postalCodeLabel + /> + | BlikCode => + | Country => + -
- | Currency(currencyArr) => - - | FullName => - getCustomFieldName} - optionalRequiredFields={Some(requiredFields)} - /> - | Email - | InfoElement - | Country - | Bank - | None - | BillingName - | PhoneNumber - | AddressLine1 - | AddressLine2 - | AddressCity - | StateAndCity - | AddressPincode - | AddressState - | BlikCode - | SpecialField(_) - | CountryAndPincode(_) - | AddressCountry(_) => React.null - }} -
- }) - ->React.array} - -
- {React.string(localeString.billingDetailsText)} -
- {dynamicFieldsToRenderInsideBilling - ->Array.mapWithIndex((item, index) => { -
Int.toString}`} - className="flex flex-col w-full place-content-between"> - {switch item { - | BillingName => - | Email => - | PhoneNumber => - | StateAndCity => -
- { - let value = ReactEvent.Form.target(ev)["value"] - setCity(prev => { - isValid: value !== "" ? Some(true) : Some(false), - value, - errorString: value !== "" ? "" : prev.errorString, - }) - }} - onBlur={ev => { - let value = ReactEvent.Focus.target(ev)["value"] - setCity(prev => { - ...prev, - isValid: Some(value !== ""), - }) - }} - paymentType - type_="text" - name="city" - inputRef=cityRef - placeholder=localeString.cityLabel - /> - {switch stateJson { - | Some(options) => - Utils.getStateNames({ - value: country, - isValid: None, - errorString: "", - })} - /> - | None => React.null - }} -
- | CountryAndPincode(countryArr) => -
- - { - let value = ReactEvent.Focus.target(ev)["value"] - setPostalCode(prev => { - ...prev, - isValid: Some(value !== ""), - }) - }} - onChange=onPostalChange - paymentType - name="postal" - inputRef=postalRef - placeholder=localeString.postalCodeLabel - /> -
- | AddressLine1 => - { - let value = ReactEvent.Form.target(ev)["value"] - setLine1(prev => { - isValid: value !== "" ? Some(true) : Some(false), - value, - errorString: value !== "" ? "" : prev.errorString, - }) - }} - onBlur={ev => { - let value = ReactEvent.Focus.target(ev)["value"] - setLine1(prev => { - ...prev, - isValid: Some(value !== ""), - }) - }} - paymentType - type_="text" - name="line1" - inputRef=line1Ref - placeholder=localeString.line1Placeholder - /> - | AddressLine2 => - { - let value = ReactEvent.Form.target(ev)["value"] - setLine2(prev => { - isValid: value !== "" ? Some(true) : Some(false), - value, - errorString: value !== "" ? "" : prev.errorString, - }) - }} - onBlur={ev => { - let value = ReactEvent.Focus.target(ev)["value"] - setLine2(prev => { - ...prev, - isValid: Some(value !== ""), - }) - }} - paymentType - type_="text" - name="line2" - inputRef=line2Ref - placeholder=localeString.line2Placeholder - /> - | AddressCity => - { - let value = ReactEvent.Form.target(ev)["value"] - setCity(prev => { - isValid: value !== "" ? Some(true) : Some(false), - value, - errorString: value !== "" ? "" : prev.errorString, - }) - }} - onBlur={ev => { - let value = ReactEvent.Focus.target(ev)["value"] - setCity(prev => { - ...prev, - isValid: Some(value !== ""), - }) - }} - paymentType - type_="text" - name="city" - inputRef=cityRef - placeholder=localeString.cityLabel - /> - | AddressState => - switch stateJson { - | Some(options) => - Utils.getStateNames({ - value: country, - isValid: None, - errorString: "", - })} - /> - | None => React.null - } - | AddressPincode => - { - let value = ReactEvent.Focus.target(ev)["value"] - setPostalCode(prev => { - ...prev, - isValid: Some(value !== ""), - }) - }} - onChange=onPostalChange - paymentType - name="postal" - inputRef=postalRef - placeholder=localeString.postalCodeLabel - /> - | BlikCode => - | Country => - - | AddressCountry(countryArr) => - - | Bank => - - | SpecialField(element) => element - | InfoElement => - <> - - {if fieldsArr->Array.length > 1 { - bottomElement - } else { - - }} - - | CardNumber - | CardExpiryMonth - | CardExpiryYear - | CardExpiryMonthAndYear - | CardCvc - | CardExpiryAndCvc - | Currency(_) - | FullName - | None => React.null + | AddressCountry(countryArr) => + + | Bank => + + | SpecialField(element) => element + | InfoElement => + <> + + {if fieldsArr->Array.length > 1 { + bottomElement + } else { + }} -
- }) - ->React.array} + + | CardNumber + | CardExpiryMonth + | CardExpiryYear + | CardExpiryMonthAndYear + | CardCvc + | CardExpiryAndCvc + | Currency(_) + | FullName + | None => React.null + }}
-
-
- - {<> - - {if fieldsArr->Array.length > 1 { - bottomElement - } else { - - }} - } - - - - - - : React.null - } + }) + ->React.array} +
+
+ + + {<> + + {if fieldsArr->Array.length > 1 { + bottomElement + } else { + + }} + } + + + + + } + } diff --git a/src/Payments/PaymentMethodsRecord.res b/src/Payments/PaymentMethodsRecord.res index 143e0413e..b77b5ddff 100644 --- a/src/Payments/PaymentMethodsRecord.res +++ b/src/Payments/PaymentMethodsRecord.res @@ -223,7 +223,7 @@ let paymentMethodsFields = [ paymentMethodName: "giropay", icon: Some(icon("giropay", ~size=19, ~width=25)), displayName: "GiroPay", - fields: [FullName, InfoElement], + fields: [InfoElement], miniIcon: None, }, { @@ -578,6 +578,7 @@ let dynamicFieldsEnabledPaymentMethods = [ "ideal", "sofort", "pix_transfer", + "giropay", ] let getIsBillingField = requiredFieldType => { diff --git a/src/Payments/PaymentMethodsWrapper.res b/src/Payments/PaymentMethodsWrapper.res index 7ee67cc8c..2c7d1710f 100644 --- a/src/Payments/PaymentMethodsWrapper.res +++ b/src/Payments/PaymentMethodsWrapper.res @@ -115,7 +115,7 @@ let make = ( )) useSubmitPaymentData(submitCallback)
Date: Thu, 4 Apr 2024 07:32:34 +0000 Subject: [PATCH 3/5] chore(release): 0.36.0 [skip ci] # [0.36.0](https://github.com/juspay/hyperswitch-web/compare/v0.35.6...v0.36.0) (2024-04-04) ### Features * **3ds:** three DS SDK - adding logs to track milestone events ([#265](https://github.com/juspay/hyperswitch-web/issues/265)) ([ceab161](https://github.com/juspay/hyperswitch-web/commit/ceab1614e80d8cfb96ac3eea04486ebd509e0770)) * giropay dynamic fields added ([#267](https://github.com/juspay/hyperswitch-web/issues/267)) ([ad2fa63](https://github.com/juspay/hyperswitch-web/commit/ad2fa630c639c7b246176f1d2683050a58ad3e36)) --- CHANGELOG.md | 8 +++ package-lock.json | 179 +++++++++++++++------------------------------- package.json | 2 +- 3 files changed, 67 insertions(+), 122 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2409ede02..b0d08ada8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# [0.36.0](https://github.com/juspay/hyperswitch-web/compare/v0.35.6...v0.36.0) (2024-04-04) + + +### Features + +* **3ds:** three DS SDK - adding logs to track milestone events ([#265](https://github.com/juspay/hyperswitch-web/issues/265)) ([ceab161](https://github.com/juspay/hyperswitch-web/commit/ceab1614e80d8cfb96ac3eea04486ebd509e0770)) +* giropay dynamic fields added ([#267](https://github.com/juspay/hyperswitch-web/issues/267)) ([ad2fa63](https://github.com/juspay/hyperswitch-web/commit/ad2fa630c639c7b246176f1d2683050a58ad3e36)) + ## [0.35.6](https://github.com/juspay/hyperswitch-web/compare/v0.35.5...v0.35.6) (2024-04-02) diff --git a/package-lock.json b/package-lock.json index 4eb12e8cd..c4bbdfe85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.35.6", + "version": "0.36.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2870,21 +2870,6 @@ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -2902,40 +2887,6 @@ "strip-ansi": "^7.0.1" } }, - "string-width-cjs": { - "version": "npm:string-width@4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, "strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -2945,23 +2896,6 @@ "ansi-regex": "^6.0.1" } }, - "strip-ansi-cjs": { - "version": "npm:strip-ansi@6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - } - } - }, "wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -2972,60 +2906,6 @@ "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } - }, - "wrap-ansi-cjs": { - "version": "npm:wrap-ansi@7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } } } }, @@ -20972,6 +20852,17 @@ "strip-ansi": "^6.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "string.prototype.matchall": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", @@ -21063,6 +20954,15 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -23630,6 +23530,43 @@ } } }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index e11908492..407624b0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.35.6", + "version": "0.36.0", "main": "index.js", "private": true, "dependencies": { From 1f082ebe2031a10129b24238f1c60fabd6f5e2e0 Mon Sep 17 00:00:00 2001 From: ArushKapoorJuspay <121166031+ArushKapoorJuspay@users.noreply.github.com> Date: Thu, 4 Apr 2024 14:11:31 +0530 Subject: [PATCH 4/5] fix: added Loader and Error Handling for TrustPay GooglePay (#268) --- src/Payments/GPay.res | 5 ++ src/Utilities/PaymentHelpers.res | 31 ++++++++-- src/orca-loader/Elements.res | 101 +++++++++++++++++++++---------- 3 files changed, 100 insertions(+), 37 deletions(-) diff --git a/src/Payments/GPay.res b/src/Payments/GPay.res index 96c540ca8..acc0c9889 100644 --- a/src/Payments/GPay.res +++ b/src/Payments/GPay.res @@ -151,6 +151,11 @@ let make = ( if result { if isInvokeSDKFlow { if isDelayedSessionToken { + handlePostMessage([ + ("fullscreen", true->JSON.Encode.bool), + ("param", "paymentloader"->JSON.Encode.string), + ("iframeId", iframeId->JSON.Encode.string), + ]) let bodyDict = PaymentBody.gPayThirdPartySdkBody(~connectors) processPayment(bodyDict) } else { diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index fa16ef0fe..86d32e11d 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -12,11 +12,18 @@ type payment = Card | BankTransfer | BankDebits | KlarnaRedirect | Gpay | Applep let closePaymentLoaderIfAny = () => Utils.handlePostMessage([("fullscreen", false->JSON.Encode.bool)]) -let retrievePaymentIntent = (clientSecret, headers, ~optLogger, ~switchToCustomPod) => { +let retrievePaymentIntent = ( + clientSecret, + headers, + ~optLogger, + ~switchToCustomPod, + ~isForceSync=false, +) => { open Promise let paymentIntentID = String.split(clientSecret, "_secret_")->Array.get(0)->Option.getOr("") let endpoint = ApiEndpoint.getApiEndPoint() - let uri = `${endpoint}/payments/${paymentIntentID}?client_secret=${clientSecret}` + let forceSync = isForceSync ? "&force_sync=true" : "" + let uri = `${endpoint}/payments/${paymentIntentID}?client_secret=${clientSecret}${forceSync}` logApi( ~optLogger, @@ -209,9 +216,15 @@ let threeDsAuth = (~clientSecret, ~optLogger, ~threeDsMethodComp, ~headers) => { }) } -let rec pollRetrievePaymentIntent = (clientSecret, headers, ~optLogger, ~switchToCustomPod) => { +let rec pollRetrievePaymentIntent = ( + clientSecret, + headers, + ~optLogger, + ~switchToCustomPod, + ~isForceSync=false, +) => { open Promise - retrievePaymentIntent(clientSecret, headers, ~optLogger, ~switchToCustomPod) + retrievePaymentIntent(clientSecret, headers, ~optLogger, ~switchToCustomPod, ~isForceSync) ->then(json => { let dict = json->JSON.Decode.object->Option.getOr(Dict.make()) let status = dict->getString("status", "") @@ -220,13 +233,19 @@ let rec pollRetrievePaymentIntent = (clientSecret, headers, ~optLogger, ~switchT resolve(json) } else { delay(2000)->then(_val => { - pollRetrievePaymentIntent(clientSecret, headers, ~optLogger, ~switchToCustomPod) + pollRetrievePaymentIntent( + clientSecret, + headers, + ~optLogger, + ~switchToCustomPod, + ~isForceSync, + ) }) } }) ->catch(e => { Console.log2("Unable to retrieve payment due to following error", e) - pollRetrievePaymentIntent(clientSecret, headers, ~optLogger, ~switchToCustomPod) + pollRetrievePaymentIntent(clientSecret, headers, ~optLogger, ~switchToCustomPod, ~isForceSync) }) } diff --git a/src/orca-loader/Elements.res b/src/orca-loader/Elements.res index 118fb1689..aa9e33e5f 100644 --- a/src/orca-loader/Elements.res +++ b/src/orca-loader/Elements.res @@ -305,40 +305,79 @@ let make = ( paymentDataRequest->GooglePayType.jsonToPaymentRequestDataType( googlePayThirdPartySession, ) - let secrets = googlePayThirdPartySession->getJsonFromDict("secrets", JSON.Encode.null) - let payment = secrets->getDictFromJson->getString("payment", "") + let headers = [("Content-Type", "application/json"), ("api-key", publishableKey)] + + let connector = + googlePayThirdPartySession + ->Dict.get("connector") + ->Option.getOr(JSON.Encode.null) + ->JSON.Decode.string + ->Option.getOr("") try { - let trustpay = trustPayApi(secrets) - trustpay.executeGooglePayment(payment, googlePayRequest) - ->then(res => { - logger.setLogInfo( - ~value="TrustPay GooglePay Success Response", - ~internalMetadata=res->JSON.stringify, - ~eventName=GOOGLE_PAY_FLOW, - ~paymentMethod="GOOGLE_PAY", - (), - ) - let msg = [("googlePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - resolve() - }) - ->catch(err => { - let exceptionMessage = err->formatException->JSON.stringify - logger.setLogInfo( - ~value=exceptionMessage, - ~eventName=GOOGLE_PAY_FLOW, - ~paymentMethod="GOOGLE_PAY", - ~logType=ERROR, - ~logCategory=USER_ERROR, - (), - ) - let msg = [("googlePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - resolve() - }) - ->ignore + switch connector { + | "trustpay" => { + let secrets = + googlePayThirdPartySession->Utils.getJsonFromDict("secrets", JSON.Encode.null) + + let payment = secrets->Utils.getDictFromJson->Utils.getString("payment", "") + + let trustpay = trustPayApi(secrets) + + let polling = + Utils.delay(2000)->then(_ => + PaymentHelpers.pollRetrievePaymentIntent( + clientSecret, + headers, + ~optLogger=Some(logger), + ~switchToCustomPod, + ~isForceSync=true, + ) + ) + let executeGooglePayment = trustpay.executeGooglePayment( + payment, + googlePayRequest, + ) + let timeOut = Utils.delay(600000)->then(_ => { + let errorMsg = + [("error", "Request Timed Out"->JSON.Encode.string)] + ->Dict.fromArray + ->JSON.Encode.object + reject(Exn.anyToExnInternal(errorMsg)) + }) + + Promise.race([polling, executeGooglePayment, timeOut]) + ->then(res => { + logger.setLogInfo( + ~value="TrustPay GooglePay Response", + ~internalMetadata=res->JSON.stringify, + ~eventName=GOOGLE_PAY_FLOW, + ~paymentMethod="GOOGLE_PAY", + (), + ) + let msg = [("googlePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + resolve() + }) + ->catch(err => { + let exceptionMessage = err->Utils.formatException->JSON.stringify + logger.setLogInfo( + ~value=exceptionMessage, + ~eventName=GOOGLE_PAY_FLOW, + ~paymentMethod="GOOGLE_PAY", + ~logType=ERROR, + ~logCategory=USER_ERROR, + (), + ) + let msg = [("googlePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + resolve() + }) + ->ignore + } + | _ => () + } } catch { | err => { let exceptionMessage = err->formatException->JSON.stringify From 7a3431305992b8d3e9c07238815158b77704ec57 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 4 Apr 2024 08:43:41 +0000 Subject: [PATCH 5/5] chore(release): 0.36.1 [skip ci] ## [0.36.1](https://github.com/juspay/hyperswitch-web/compare/v0.36.0...v0.36.1) (2024-04-04) ### Bug Fixes * added Loader and Error Handling for TrustPay GooglePay ([#268](https://github.com/juspay/hyperswitch-web/issues/268)) ([1f082eb](https://github.com/juspay/hyperswitch-web/commit/1f082ebe2031a10129b24238f1c60fabd6f5e2e0)) --- CHANGELOG.md | 7 ++ package-lock.json | 179 +++++++++++++++++++++++++++++++--------------- package.json | 2 +- 3 files changed, 129 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0d08ada8..cba71aa67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [0.36.1](https://github.com/juspay/hyperswitch-web/compare/v0.36.0...v0.36.1) (2024-04-04) + + +### Bug Fixes + +* added Loader and Error Handling for TrustPay GooglePay ([#268](https://github.com/juspay/hyperswitch-web/issues/268)) ([1f082eb](https://github.com/juspay/hyperswitch-web/commit/1f082ebe2031a10129b24238f1c60fabd6f5e2e0)) + # [0.36.0](https://github.com/juspay/hyperswitch-web/compare/v0.35.6...v0.36.0) (2024-04-04) diff --git a/package-lock.json b/package-lock.json index c4bbdfe85..101fe6213 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.36.0", + "version": "0.36.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2870,6 +2870,21 @@ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -2887,6 +2902,40 @@ "strip-ansi": "^7.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, "strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", @@ -2896,6 +2945,23 @@ "ansi-regex": "^6.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + } + } + }, "wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -2906,6 +2972,60 @@ "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } } } }, @@ -20852,17 +20972,6 @@ "strip-ansi": "^6.0.1" } }, - "string-width-cjs": { - "version": "npm:string-width@4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, "string.prototype.matchall": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", @@ -20954,15 +21063,6 @@ "ansi-regex": "^5.0.1" } }, - "strip-ansi-cjs": { - "version": "npm:strip-ansi@6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, "strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -23530,43 +23630,6 @@ } } }, - "wrap-ansi-cjs": { - "version": "npm:wrap-ansi@7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 407624b0d..de47c185c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.36.0", + "version": "0.36.1", "main": "index.js", "private": true, "dependencies": {