From 7a19970370defa9eebd31eccfd8813b0d998a36a Mon Sep 17 00:00:00 2001 From: Arush Date: Mon, 27 May 2024 14:35:20 +0530 Subject: [PATCH] fix: added Fixes for one click widgets --- src/CardUtils.res | 2 +- src/LoaderController.res | 2 +- src/Payments/ApplePay.res | 11 +++- src/Payments/GPay.res | 10 +++- src/RenderPaymentMethods.res | 2 +- src/Types/ApplePayTypes.res | 106 +++++++++++++++++++++++------------ src/Types/CardThemeType.res | 6 +- src/Types/GooglePayType.res | 28 +++++++++ src/Utilities/Utils.res | 4 +- src/Window.res | 6 +- src/orca-loader/Elements.res | 96 +++++++++---------------------- src/orca-loader/Types.res | 2 +- 12 files changed, 158 insertions(+), 117 deletions(-) diff --git a/src/CardUtils.res b/src/CardUtils.res index 0fc186571..d60723150 100644 --- a/src/CardUtils.res +++ b/src/CardUtils.res @@ -361,7 +361,7 @@ let getCardBrandIcon = (cardType, paymentType) => { | GooglePayElement | PayPalElement | ApplePayElement - | PaymentRequestButtonsElement + | ExpressCheckoutElement | NONE => } diff --git a/src/LoaderController.res b/src/LoaderController.res index 28551bc9e..530066a3c 100644 --- a/src/LoaderController.res +++ b/src/LoaderController.res @@ -82,7 +82,7 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime | GooglePayElement | PayPalElement | ApplePayElement - | PaymentRequestButtonsElement + | ExpressCheckoutElement | Payment => { let paymentOptions = PaymentType.itemToObjMapper(optionsDict, logger) setOptionsPayment(_ => paymentOptions) diff --git a/src/Payments/ApplePay.res b/src/Payments/ApplePay.res index 3547fe569..dc8c3c7a5 100644 --- a/src/Payments/ApplePay.res +++ b/src/Payments/ApplePay.res @@ -2,6 +2,8 @@ open Utils open Promise @react.component let make = (~sessionObj: option) => { + let url = RescriptReactRouter.useUrl() + let componentName = CardUtils.getQueryParamsDictforKey(url.search, "componentName") let loggerState = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom) let {publishableKey, sdkHandleOneClickConfirmPayment} = Recoil.useRecoilValueFromAtom( RecoilAtoms.keys, @@ -242,7 +244,14 @@ let make = (~sessionObj: option) => { let bodyDict = PaymentBody.applePayThirdPartySdkBody(~connectors) processPayment(bodyDict, ~isThirdPartyFlow=true, ()) } else { - let message = [("applePayButtonClicked", true->JSON.Encode.bool)] + let paymentRequest = ApplePayTypes.getPaymentRequestFromSession( + ~sessionObj, + ~componentName, + ) + let message = [ + ("applePayButtonClicked", true->JSON.Encode.bool), + ("applePayPaymentRequest", paymentRequest), + ] handlePostMessage(message) } } else { diff --git a/src/Payments/GPay.res b/src/Payments/GPay.res index f7f80a5bc..aa3782079 100644 --- a/src/Payments/GPay.res +++ b/src/Payments/GPay.res @@ -6,6 +6,8 @@ open Promise @react.component let make = (~sessionObj: option, ~thirdPartySessionObj: option) => { + let url = RescriptReactRouter.useUrl() + let componentName = CardUtils.getQueryParamsDictforKey(url.search, "componentName") let loggerState = Recoil.useRecoilValueFromAtom(loggerAtom) let {iframeId} = Recoil.useRecoilValueFromAtom(keys) let {publishableKey, sdkHandleOneClickConfirmPayment} = Recoil.useRecoilValueFromAtom(keys) @@ -183,12 +185,18 @@ let make = (~sessionObj: option, ~thirdPartySessionObj: opti let bodyDict = PaymentBody.gPayThirdPartySdkBody(~connectors) processPayment(bodyDict, ~isThirdPartyFlow=true, ()) } else { + let paymentDataRequest = getPaymentDataFromSession(~sessionObj, ~componentName) handlePostMessage([ ("fullscreen", true->JSON.Encode.bool), ("param", "paymentloader"->JSON.Encode.string), ("iframeId", iframeId->JSON.Encode.string), ]) - options.readOnly ? () : handlePostMessage([("GpayClicked", true->JSON.Encode.bool)]) + if !options.readOnly { + handlePostMessage([ + ("GpayClicked", true->JSON.Encode.bool), + ("GpayPaymentDataRequest", paymentDataRequest->Identity.anyTypeToJson), + ]) + } } } else { let bodyDict = PaymentBody.gpayRedirectBody(~connectors) diff --git a/src/RenderPaymentMethods.res b/src/RenderPaymentMethods.res index f4185a6fd..960c0d720 100644 --- a/src/RenderPaymentMethods.res +++ b/src/RenderPaymentMethods.res @@ -82,7 +82,7 @@ let make = ( | GooglePayElement | PayPalElement | ApplePayElement - | PaymentRequestButtonsElement + | ExpressCheckoutElement | Payment => diff --git a/src/Types/ApplePayTypes.res b/src/Types/ApplePayTypes.res index 8865aaffc..d7a4040eb 100644 --- a/src/Types/ApplePayTypes.res +++ b/src/Types/ApplePayTypes.res @@ -1,3 +1,5 @@ +open Utils + type token = {paymentData: JSON.t} type billingContact = { addressLines: array, @@ -65,41 +67,41 @@ type paymentRequestData = { let jsonToPaymentRequestDataType: Dict.t => paymentRequestData = jsonDict => { let clientTimeZone = CardUtils.dateTimeFormat().resolvedOptions().timeZone - let clientCountry = Utils.getClientCountry(clientTimeZone) + let clientCountry = getClientCountry(clientTimeZone) let defaultCountryCode = clientCountry.isoAlpha2 let getTotal = totalDict => { - Utils.getString(totalDict, "type", "") == "" + getString(totalDict, "type", "") == "" ? total( - ~label=Utils.getString(totalDict, "label", ""), - ~amount=Utils.getString(totalDict, "amount", ""), + ~label=getString(totalDict, "label", ""), + ~amount=getString(totalDict, "amount", ""), (), ) : total( - ~label=Utils.getString(totalDict, "label", ""), - ~amount=Utils.getString(totalDict, "amount", ""), - ~\"type"=Utils.getString(totalDict, "type", ""), + ~label=getString(totalDict, "label", ""), + ~amount=getString(totalDict, "amount", ""), + ~\"type"=getString(totalDict, "type", ""), (), ) } - if Utils.getString(jsonDict, "merchant_identifier", "") == "" { + if getString(jsonDict, "merchant_identifier", "") == "" { paymentRequestData( - ~countryCode=Utils.getString(jsonDict, "country_code", defaultCountryCode), - ~currencyCode=Utils.getString(jsonDict, "currency_code", ""), - ~merchantCapabilities=Utils.getStrArray(jsonDict, "merchant_capabilities"), - ~supportedNetworks=Utils.getStrArray(jsonDict, "supported_networks"), - ~total=getTotal(jsonDict->Utils.getDictFromObj("total")), + ~countryCode=getString(jsonDict, "country_code", defaultCountryCode), + ~currencyCode=getString(jsonDict, "currency_code", ""), + ~merchantCapabilities=getStrArray(jsonDict, "merchant_capabilities"), + ~supportedNetworks=getStrArray(jsonDict, "supported_networks"), + ~total=getTotal(jsonDict->getDictFromObj("total")), (), ) } else { paymentRequestData( - ~countryCode=Utils.getString(jsonDict, "country_code", ""), - ~currencyCode=Utils.getString(jsonDict, "currency_code", ""), - ~merchantCapabilities=Utils.getStrArray(jsonDict, "merchant_capabilities"), - ~supportedNetworks=Utils.getStrArray(jsonDict, "supported_networks"), - ~total=getTotal(jsonDict->Utils.getDictFromObj("total")), - ~merchantIdentifier=Utils.getString(jsonDict, "merchant_identifier", ""), + ~countryCode=getString(jsonDict, "country_code", ""), + ~currencyCode=getString(jsonDict, "currency_code", ""), + ~merchantCapabilities=getStrArray(jsonDict, "merchant_capabilities"), + ~supportedNetworks=getStrArray(jsonDict, "supported_networks"), + ~total=getTotal(jsonDict->getDictFromObj("total")), + ~merchantIdentifier=getString(jsonDict, "merchant_identifier", ""), (), ) } @@ -107,26 +109,60 @@ let jsonToPaymentRequestDataType: Dict.t => paymentRequestData = jsonDic let billingContactItemToObjMapper = dict => { { - addressLines: dict->Utils.getStrArray("addressLines"), - administrativeArea: dict->Utils.getString("administrativeArea", ""), - countryCode: dict->Utils.getString("countryCode", ""), - familyName: dict->Utils.getString("familyName", ""), - givenName: dict->Utils.getString("givenName", ""), - locality: dict->Utils.getString("locality", ""), - postalCode: dict->Utils.getString("postalCode", ""), + addressLines: dict->getStrArray("addressLines"), + administrativeArea: dict->getString("administrativeArea", ""), + countryCode: dict->getString("countryCode", ""), + familyName: dict->getString("familyName", ""), + givenName: dict->getString("givenName", ""), + locality: dict->getString("locality", ""), + postalCode: dict->getString("postalCode", ""), } } let shippingContactItemToObjMapper = dict => { { - emailAddress: dict->Utils.getString("emailAddress", ""), - phoneNumber: dict->Utils.getString("phoneNumber", ""), - addressLines: dict->Utils.getStrArray("addressLines"), - administrativeArea: dict->Utils.getString("administrativeArea", ""), - countryCode: dict->Utils.getString("countryCode", ""), - familyName: dict->Utils.getString("familyName", ""), - givenName: dict->Utils.getString("givenName", ""), - locality: dict->Utils.getString("locality", ""), - postalCode: dict->Utils.getString("postalCode", ""), + emailAddress: dict->getString("emailAddress", ""), + phoneNumber: dict->getString("phoneNumber", ""), + addressLines: dict->getStrArray("addressLines"), + administrativeArea: dict->getString("administrativeArea", ""), + countryCode: dict->getString("countryCode", ""), + familyName: dict->getString("familyName", ""), + givenName: dict->getString("givenName", ""), + locality: dict->getString("locality", ""), + postalCode: dict->getString("postalCode", ""), } } + +let getPaymentRequestFromSession = (~sessionObj, ~componentName) => { + let paymentRequest = + sessionObj + ->Option.flatMap(JSON.Decode.object) + ->Option.getOr(Dict.make()) + ->Dict.get("payment_request_data") + ->Option.getOr(Dict.make()->JSON.Encode.object) + ->transformKeys(CamelCase) + + let requiredShippingContactFields = + paymentRequest + ->getDictFromJson + ->getStrArray("requiredShippingContactFields") + + if ( + componentName->getIsExpressCheckoutComponent->not && + requiredShippingContactFields->Array.length !== 0 + ) { + let shippingFieldsWithoutPostalAddress = + requiredShippingContactFields->Array.filter(item => item !== "postalAddress") + + paymentRequest + ->getDictFromJson + ->Dict.set( + "requiredShippingContactFields", + shippingFieldsWithoutPostalAddress + ->getArrofJsonString + ->JSON.Encode.array, + ) + } + + paymentRequest +} diff --git a/src/Types/CardThemeType.res b/src/Types/CardThemeType.res index fc815e3d7..176f73d87 100644 --- a/src/Types/CardThemeType.res +++ b/src/Types/CardThemeType.res @@ -14,7 +14,7 @@ type mode = | GooglePayElement | PayPalElement | ApplePayElement - | PaymentRequestButtonsElement + | ExpressCheckoutElement | NONE type label = Above | Floating | Never type themeClass = { @@ -98,7 +98,7 @@ let getPaymentMode = val => { | "googlePay" => GooglePayElement | "payPal" => PayPalElement | "applePay" => ApplePayElement - | "paymentRequestButtons" => PaymentRequestButtonsElement + | "expressCheckout" => ExpressCheckoutElement | _ => NONE } } @@ -113,7 +113,7 @@ let getPaymentModeToStrMapper = val => { | GooglePayElement => "GooglePayElement" | PayPalElement => "PayPalElement" | ApplePayElement => "ApplePayElement" - | PaymentRequestButtonsElement => "PaymentRequestButtonsElement" + | ExpressCheckoutElement => "ExpressCheckoutElement" | NONE => "None" } } diff --git a/src/Types/GooglePayType.res b/src/Types/GooglePayType.res index 5669b17d9..f018a61e0 100644 --- a/src/Types/GooglePayType.res +++ b/src/Types/GooglePayType.res @@ -156,3 +156,31 @@ let billingContactItemToObjMapper = dict => { sortingCode: dict->getString("sortingCode", ""), } } + +let baseRequest = { + "apiVersion": 2, + "apiVersionMinor": 0, +} + +let getPaymentDataFromSession = (~sessionObj, ~componentName) => { + let gpayobj = switch sessionObj { + | Some(val) => val + | _ => SessionsType.defaultToken + } + let paymentDataRequest = assign2( + Dict.make()->JSON.Encode.object, + baseRequest->Identity.anyTypeToJson, + ) + paymentDataRequest.allowedPaymentMethods = gpayobj.allowed_payment_methods->arrayJsonToCamelCase + paymentDataRequest.transactionInfo = gpayobj.transaction_info->transformKeys(CamelCase) + paymentDataRequest.merchantInfo = gpayobj.merchant_info->transformKeys(CamelCase) + paymentDataRequest.emailRequired = gpayobj.emailRequired + + if componentName->getIsExpressCheckoutComponent { + paymentDataRequest.shippingAddressRequired = gpayobj.shippingAddressRequired + paymentDataRequest.shippingAddressParameters = + gpayobj.shippingAddressParameters->transformKeys(CamelCase) + } + + paymentDataRequest +} diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res index 35531437c..d2661b56b 100644 --- a/src/Utilities/Utils.res +++ b/src/Utilities/Utils.res @@ -1230,7 +1230,7 @@ let getWalletPaymentMethod = (wallets, paymentType: CardThemeType.mode) => { } } -let expressCheckoutComponents = ["googlePay", "payPal", "applePay", "paymentRequestButtons"] +let expressCheckoutComponents = ["googlePay", "payPal", "applePay", "expressCheckout"] let componentsForPaymentElementCreate = ["payment"]->Array.concat(expressCheckoutComponents) @@ -1246,7 +1246,7 @@ let walletElementPaymentType: array = [ GooglePayElement, PayPalElement, ApplePayElement, - PaymentRequestButtonsElement, + ExpressCheckoutElement, ] let getIsWalletElementPaymentType = (paymentType: CardThemeType.mode) => { diff --git a/src/Window.res b/src/Window.res index b9548f95e..16e00bab9 100644 --- a/src/Window.res +++ b/src/Window.res @@ -60,13 +60,17 @@ external style: Dom.element => style = "style" @send external paymentRequest: (JSON.t, JSON.t, JSON.t) => JSON.t = "PaymentRequest" @send external click: Dom.element => unit = "click" +let sendPostMessage = (element, message) => { + element->postMessage(message->JSON.Encode.object->JSON.stringify, GlobalVars.targetOrigin) +} + let iframePostMessage = (iframeRef: nullable, message) => { switch iframeRef->Nullable.toOption { | Some(ref) => try { ref ->contentWindow - ->postMessage(message->JSON.Encode.object->JSON.stringify, GlobalVars.targetOrigin) + ->sendPostMessage(message) } catch { | _ => () } diff --git a/src/orca-loader/Elements.res b/src/orca-loader/Elements.res index cb5caf2bd..6e10cd1f6 100644 --- a/src/orca-loader/Elements.res +++ b/src/orca-loader/Elements.res @@ -256,7 +256,7 @@ let make = ( | "googlePay" | "payPal" | "applePay" - | "paymentRequestButtons" + | "expressCheckout" | "payment" => () | str => manageErrorWarning(UNKNOWN_KEY, ~dynamicStr=`${str} type in create`, ~logger, ()) } @@ -312,7 +312,7 @@ let make = ( try { if session.canMakePayments() { let msg = [("applePayCanMakePayments", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) } else { Console.log("CANNOT MAKE PAYMENT USING APPLE PAY") logger.setLogInfo( @@ -430,7 +430,7 @@ let make = ( (), ) let msg = [("googlePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) resolve() }) ->catch(err => { @@ -444,7 +444,7 @@ let make = ( (), ) let msg = [("googlePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) resolve() }) ->ignore @@ -463,7 +463,7 @@ let make = ( (), ) let msg = [("googlePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) } } } @@ -557,7 +557,7 @@ let make = ( (), ) let msg = [("applePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) resolve() }) ->catch(err => { @@ -569,7 +569,7 @@ let make = ( (), ) let msg = [("applePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) resolve() }) ->ignore @@ -582,7 +582,7 @@ let make = ( (), ) let msg = [("applePaySyncPayment", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) } } | _ => () @@ -765,14 +765,17 @@ let make = ( ("applePayBillingContact", payment.billingContact), ("applePayShippingContact", payment.shippingContact), ]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) } let handleApplePayMessages = (event: Types.event) => { let json = event.data->Identity.anyTypeToJson let dict = json->getDictFromJson - switch dict->Dict.get("applePayButtonClicked") { - | Some(val) => + switch ( + dict->Dict.get("applePayButtonClicked"), + dict->Dict.get("applePayPaymentRequest"), + ) { + | (Some(val), Some(paymentRequest)) => if val->JSON.Decode.bool->Belt.Option.getWithDefault(false) { let isDelayedSessionToken = applePayPresent @@ -789,37 +792,6 @@ let make = ( ~paymentMethod="APPLE_PAY", (), ) - let paymentRequest = - applePayPresent - ->Belt.Option.flatMap(JSON.Decode.object) - ->Belt.Option.getWithDefault(Dict.make()) - ->Dict.get("payment_request_data") - ->Belt.Option.getWithDefault(Dict.make()->JSON.Encode.object) - ->transformKeys(CamelCase) - - let requiredShippingContactFields = - paymentRequest - ->Utils.getDictFromJson - ->Utils.getStrArray("requiredShippingContactFields") - - if ( - componentType->getIsExpressCheckoutComponent->not && - requiredShippingContactFields->Array.length !== 0 - ) { - let requiredShippingContactFields = - requiredShippingContactFields->Array.filter(item => - item !== "postalAddress" - ) - - paymentRequest - ->Utils.getDictFromJson - ->Dict.set( - "requiredShippingContactFields", - requiredShippingContactFields - ->Utils.getArrofJsonString - ->JSON.Encode.array, - ) - } let ssn = applePaySession(3, paymentRequest) switch applePaySessionRef.contents->Nullable.toOption { @@ -862,7 +834,7 @@ let make = ( ssn.oncancel = _ev => { let msg = [("showApplePayButton", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) applePaySessionRef := Nullable.null logInfo(Console.log("Apple Pay Payment Cancelled")) logger.setLogInfo( @@ -877,7 +849,7 @@ let make = ( } else { () } - | None => () + | _ => () } } @@ -902,34 +874,13 @@ let make = ( | _ => SessionsType.defaultToken } - let baseRequest = { - "apiVersion": 2, - "apiVersionMinor": 0, - } - let paymentDataRequest = GooglePayType.assign2( - Dict.make()->JSON.Encode.object, - baseRequest->Identity.anyTypeToJson, - ) - let payRequest = GooglePayType.assign( Dict.make()->JSON.Encode.object, - baseRequest->Identity.anyTypeToJson, + GooglePayType.baseRequest->Identity.anyTypeToJson, { "allowedPaymentMethods": gpayobj.allowed_payment_methods->arrayJsonToCamelCase, }->Identity.anyTypeToJson, ) - paymentDataRequest.allowedPaymentMethods = - gpayobj.allowed_payment_methods->arrayJsonToCamelCase - paymentDataRequest.transactionInfo = - gpayobj.transaction_info->transformKeys(CamelCase) - paymentDataRequest.merchantInfo = gpayobj.merchant_info->transformKeys(CamelCase) - paymentDataRequest.emailRequired = gpayobj.emailRequired - - if componentType->getIsExpressCheckoutComponent { - paymentDataRequest.shippingAddressRequired = gpayobj.shippingAddressRequired - paymentDataRequest.shippingAddressParameters = - gpayobj.shippingAddressParameters->transformKeys(CamelCase) - } try { let gPayClient = GooglePayType.google( @@ -967,13 +918,18 @@ let make = ( ->getOptionalJsonFromJson("GpayClicked") ->getBoolFromJson(false) - if gpayClicked { + let paymentDataRequest = + evJson + ->getOptionalJsonFromJson("GpayPaymentDataRequest") + ->Option.getOr(JSON.Encode.null) + + if gpayClicked && paymentDataRequest !== JSON.Encode.null { setTimeout(() => { - gPayClient.loadPaymentData(paymentDataRequest->anyTypeToJson) + gPayClient.loadPaymentData(paymentDataRequest) ->then( json => { let msg = [("gpayResponse", json->anyTypeToJson)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) let value = "Payment Data Filled: New Payment Method" logger.setLogInfo( ~value, @@ -995,7 +951,7 @@ let make = ( ) let msg = [("gpayError", err->anyTypeToJson)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) + event.source->Window.sendPostMessage(msg) resolve() }, ) diff --git a/src/orca-loader/Types.res b/src/orca-loader/Types.res index af364c201..ced9a31e4 100644 --- a/src/orca-loader/Types.res +++ b/src/orca-loader/Types.res @@ -10,7 +10,7 @@ type eventData = { confirmTriggered: bool, oneClickConfirmTriggered: bool, } -type event = {key: string, data: eventData} +type event = {key: string, data: eventData, source: Dom.element} type eventParam = Event(event) | EventData(eventData) | Empty type eventHandler = option => unit @send external onload: (Dom.element, unit => Promise.t<'a>) => Promise.t<'a> = "onload"