From 1d491e1254b7789ae72412e52c8f738bdf0a22e0 Mon Sep 17 00:00:00 2001 From: rising-dragon401 Date: Tue, 30 Apr 2024 19:24:32 +0530 Subject: [PATCH] feat: added one click widgets (applepay, googlepay, paypal) (#271) Co-authored-by: Vrishab Srivatsa Co-authored-by: Praful Koppalkar <126236898+prafulkoppalkar@users.noreply.github.com> --- src/App.res | 7 +- src/CardTheme.res | 11 -- src/CardUtils.res | 4 + src/Components/DynamicFields.res | 2 +- src/Components/SavedMethods.res | 2 +- src/LoaderController.res | 11 +- src/PaymentElement.res | 49 +-------- src/PaymentElementRenderer.res | 9 +- src/RenderPaymentMethods.res | 8 +- src/ThreeDSAuth.res | 2 +- src/ThreeDSMethod.res | 2 +- src/Types/CardThemeType.res | 34 +++++++ src/Types/PaymentType.res | 8 +- src/Utilities/DynamicFieldsUtils.res | 21 ---- src/Utilities/PaymentHelpers.res | 26 ++++- src/Utilities/PaymentUtils.res | 92 ++++++++++++++++- src/Utilities/Utils.res | 28 ++++++ src/WalletElement.res | 41 ++++++++ src/orca-loader/Elements.res | 123 ++++++++++++++++------- src/orca-loader/LoaderPaymentElement.res | 14 +-- src/orca-log-catcher/OrcaLogger.res | 41 +++++--- 21 files changed, 374 insertions(+), 161 deletions(-) create mode 100644 src/WalletElement.res diff --git a/src/App.res b/src/App.res index 904b641..539bd21 100644 --- a/src/App.res +++ b/src/App.res @@ -1,13 +1,14 @@ @react.component let make = () => { - let (logger, initTimestamp) = React.useMemo0(() => { - (OrcaLogger.make(), Date.now()) - }) let url = RescriptReactRouter.useUrl() let (integrateError, setIntegrateErrorError) = React.useState(() => false) let setLoggerState = Recoil.useSetRecoilState(RecoilAtoms.loggerAtom) let paymentMode = CardUtils.getQueryParamsDictforKey(url.search, "componentName") + let paymentType = paymentMode->CardThemeType.getPaymentMode + let (logger, initTimestamp) = React.useMemo0(() => { + (OrcaLogger.make(~source=Elements(paymentType), ()), Date.now()) + }) let fullscreenMode = CardUtils.getQueryParamsDictforKey(url.search, "fullscreenType") React.useEffect(() => { diff --git a/src/CardTheme.res b/src/CardTheme.res index 4378a1e..1b1e3e0 100644 --- a/src/CardTheme.res +++ b/src/CardTheme.res @@ -32,17 +32,6 @@ let getShowLoader = (str, logger) => { } } -let getPaymentMode = val => { - switch val { - | "card" => Card - | "payment" => Payment - | "cardNumber" => CardNumberElement - | "cardExpiry" => CardExpiryElement - | "cardCvc" => CardCVCElement - | _ => NONE - } -} - let defaultAppearance = { theme: Default, variables: DefaultTheme.default, diff --git a/src/CardUtils.res b/src/CardUtils.res index b77f1d6..20d6196 100644 --- a/src/CardUtils.res +++ b/src/CardUtils.res @@ -338,6 +338,10 @@ let getCardBrandIcon = (cardType, paymentType) => { | CardNumberElement | CardExpiryElement | CardCVCElement + | GooglePayElement + | PayPalElement + | ApplePayElement + | PaymentRequestButtonsElement | NONE => } diff --git a/src/Components/DynamicFields.res b/src/Components/DynamicFields.res index 0a5a1dc..b5b6a33 100644 --- a/src/Components/DynamicFields.res +++ b/src/Components/DynamicFields.res @@ -22,7 +22,7 @@ let make = ( let {billingAddress} = Recoil.useRecoilValueFromAtom(optionAtom) //<...>// - let paymentMethodTypes = DynamicFieldsUtils.usePaymentMethodTypeFromList( + let paymentMethodTypes = PaymentUtils.usePaymentMethodTypeFromList( ~list, ~paymentMethod, ~paymentMethodType, diff --git a/src/Components/SavedMethods.res b/src/Components/SavedMethods.res index 6ac0cca..7178e49 100644 --- a/src/Components/SavedMethods.res +++ b/src/Components/SavedMethods.res @@ -55,7 +55,7 @@ let make = ( | Some(ele) => ele | None => "" }->getCardType, - ""->CardTheme.getPaymentMode, + ""->CardThemeType.getPaymentMode, ) } let isActive = token == obj.paymentToken diff --git a/src/LoaderController.res b/src/LoaderController.res index 977ec3c..ba1ef77 100644 --- a/src/LoaderController.res +++ b/src/LoaderController.res @@ -73,12 +73,16 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime let updateOptions = dict => { let optionsDict = dict->getDictFromObj("options") - switch paymentMode->CardTheme.getPaymentMode { + switch paymentMode->CardThemeType.getPaymentMode { | CardNumberElement | CardExpiryElement | CardCVCElement | Card => setOptions(_ => ElementType.itemToObjMapper(optionsDict, logger)) + | GooglePayElement + | PayPalElement + | ApplePayElement + | PaymentRequestButtonsElement | Payment => { let paymentOptions = PaymentType.itemToObjMapper(optionsDict, logger) setOptionsPayment(_ => paymentOptions) @@ -176,7 +180,7 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime if dict->Dict.toArray->Array.length > 0 { generateStyleSheet("", dict, "themestyle") } - switch paymentMode->CardTheme.getPaymentMode { + switch paymentMode->CardThemeType.getPaymentMode { | Payment => () | _ => let styleClass = [ @@ -493,8 +497,9 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime } React.useEffect(() => { + let iframeHeight = divH->Float.equal(0.0) ? divH : divH +. 1.0 handlePostMessage([ - ("iframeHeight", (divH +. 1.0)->JSON.Encode.float), + ("iframeHeight", iframeHeight->JSON.Encode.float), ("iframeId", iframeId->JSON.Encode.string), ]) None diff --git a/src/PaymentElement.res b/src/PaymentElement.res index 04a3cd0..28bdbc6 100644 --- a/src/PaymentElement.res +++ b/src/PaymentElement.res @@ -19,10 +19,7 @@ let make = (~cardProps, ~expiryProps, ~cvcProps, ~paymentType: CardThemeType.mod } = Recoil.useRecoilValueFromAtom(optionAtom) let {themeObj, localeString} = Recoil.useRecoilValueFromAtom(configAtom) let optionAtomValue = Recoil.useRecoilValueFromAtom(optionAtom) - let isApplePayReady = Recoil.useRecoilValueFromAtom(isApplePayReady) - let isGooglePayReady = Recoil.useRecoilValueFromAtom(isGooglePayReady) let methodslist = Recoil.useRecoilValueFromAtom(list) - let paymentOrder = paymentMethodOrder->getOptionalArr->removeDuplicate let (sessions, setSessions) = React.useState(_ => Dict.make()->JSON.Encode.object) let (paymentOptions, setPaymentOptions) = React.useState(_ => []) let (walletOptions, setWalletOptions) = React.useState(_ => []) @@ -102,52 +99,12 @@ let make = (~cardProps, ~expiryProps, ~cvcProps, ~paymentType: CardThemeType.mod None }, [savedMethods]) - let areAllGooglePayRequiredFieldsPrefilled = DynamicFieldsUtils.useAreAllRequiredFieldsPrefilled( + let (walletList, paymentOptionsList, actualList) = PaymentUtils.useGetPaymentMethodList( ~list, - ~paymentMethod="wallet", - ~paymentMethodType="google_pay", + ~paymentOptions, + ~paymentType, ) - let areAllApplePayRequiredFieldsPrefilled = DynamicFieldsUtils.useAreAllRequiredFieldsPrefilled( - ~list, - ~paymentMethod="wallet", - ~paymentMethodType="apple_pay", - ) - - let (walletList, paymentOptionsList, actualList) = React.useMemo(() => { - switch methodslist { - | Loaded(paymentlist) => - let paymentOrder = - paymentOrder->Array.length > 0 ? paymentOrder : PaymentModeType.defaultOrder - let plist = paymentlist->getDictFromJson->PaymentMethodsRecord.itemToObjMapper - let (wallets, otherOptions) = - plist->PaymentUtils.paymentListLookupNew( - ~order=paymentOrder, - ~showApplePay=isApplePayReady, - ~showGooglePay=isGooglePayReady, - ~areAllGooglePayRequiredFieldsPrefilled, - ~areAllApplePayRequiredFieldsPrefilled, - ) - ( - wallets->removeDuplicate, - paymentOptions->Array.concat(otherOptions)->removeDuplicate, - otherOptions, - ) - | SemiLoaded => - showCardFormByDefault && checkPriorityList(paymentMethodOrder) - ? ([], ["card"], []) - : ([], [], []) - | _ => ([], [], []) - } - }, ( - methodslist, - paymentMethodOrder, - isApplePayReady, - isGooglePayReady, - areAllGooglePayRequiredFieldsPrefilled, - areAllApplePayRequiredFieldsPrefilled, - )) - React.useEffect(() => { switch methodslist { | Loaded(paymentlist) => diff --git a/src/PaymentElementRenderer.res b/src/PaymentElementRenderer.res index ed3bbfb..da2d15a 100644 --- a/src/PaymentElementRenderer.res +++ b/src/PaymentElementRenderer.res @@ -15,9 +15,14 @@ let make = ( switch (sessions, list) { | (_, Loading) => - + {paymentType->Utils.isWalletElementPaymentType + ? + : } - | _ => + | _ => + paymentType->Utils.isWalletElementPaymentType + ? + : } } diff --git a/src/RenderPaymentMethods.res b/src/RenderPaymentMethods.res index 9e72ab0..94c282c 100644 --- a/src/RenderPaymentMethods.res +++ b/src/RenderPaymentMethods.res @@ -79,10 +79,16 @@ let make = ( paymentType cardProps expiryProps cvcProps zipProps handleElementFocus isFocus /> + | GooglePayElement + | PayPalElement + | ApplePayElement + | PaymentRequestButtonsElement | Payment => - + {paymentType->Utils.isWalletElementPaymentType + ? + : } }> diff --git a/src/ThreeDSAuth.res b/src/ThreeDSAuth.res index f9495e8..a763a8a 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 = OrcaLogger.make() + let logger = OrcaLogger.make(~source=Elements(Payment), ()) React.useEffect0(() => { handlePostMessage([("iframeMountedCallback", true->JSON.Encode.bool)]) diff --git a/src/ThreeDSMethod.res b/src/ThreeDSMethod.res index e024fd7..a46696e 100644 --- a/src/ThreeDSMethod.res +++ b/src/ThreeDSMethod.res @@ -1,7 +1,7 @@ open Utils @react.component let make = () => { - let logger = OrcaLogger.make() + let logger = OrcaLogger.make(~source=Elements(Payment), ()) let (stateMetadata, setStateMetadata) = React.useState(_ => Dict.make()->JSON.Encode.object) diff --git a/src/Types/CardThemeType.res b/src/Types/CardThemeType.res index 7001fcb..3290cfd 100644 --- a/src/Types/CardThemeType.res +++ b/src/Types/CardThemeType.res @@ -9,6 +9,10 @@ type mode = | CardNumberElement | CardExpiryElement | CardCVCElement + | GooglePayElement + | PayPalElement + | ApplePayElement + | PaymentRequestButtonsElement | NONE type label = Above | Floating | Never type themeClass = { @@ -80,3 +84,33 @@ type configClass = { fonts: array, loader: showLoader, } + +let getPaymentMode = val => { + switch val { + | "card" => Card + | "payment" => Payment + | "cardNumber" => CardNumberElement + | "cardExpiry" => CardExpiryElement + | "cardCvc" => CardCVCElement + | "googlePay" => GooglePayElement + | "payPal" => PayPalElement + | "applePay" => ApplePayElement + | "paymentRequestButtons" => PaymentRequestButtonsElement + | _ => NONE + } +} + +let getPaymentModeToStrMapper = val => { + switch val { + | Card => "Card" + | Payment => "Payment" + | CardNumberElement => "CardNumberElement" + | CardExpiryElement => "CardExpiryElement" + | CardCVCElement => "CardCVCElement" + | GooglePayElement => "GooglePayElement" + | PayPalElement => "PayPalElement" + | ApplePayElement => "ApplePayElement" + | PaymentRequestButtonsElement => "PaymentRequestButtonsElement" + | NONE => "None" + } +} diff --git a/src/Types/PaymentType.res b/src/Types/PaymentType.res index b17ca0f..7c7a5d5 100644 --- a/src/Types/PaymentType.res +++ b/src/Types/PaymentType.res @@ -92,6 +92,7 @@ type wallets = { walletReturnUrl: string, applePay: showType, googlePay: showType, + payPal: showType, style: style, } type business = {name: string} @@ -257,6 +258,7 @@ let defaultWallets = { walletReturnUrl: "", applePay: Auto, googlePay: Auto, + payPal: Auto, style: defaultStyle, } let defaultBillingAddress = { @@ -743,7 +745,7 @@ let getWallets = (dict, str, logger) => { ->Option.flatMap(JSON.Decode.object) ->Option.map(json => { unknownKeysWarning( - ["applePay", "googlePay", "style", "walletReturnUrl"], + ["applePay", "googlePay", "style", "walletReturnUrl", "payPal"], json, "options.wallets", ~logger, @@ -759,6 +761,10 @@ let getWallets = (dict, str, logger) => { "options.wallets.googlePay", logger, ), + payPal: getWarningString(json, "payPal", "auto", ~logger)->getShowType( + "options.wallets.payPal", + logger, + ), style: getStyle(json, "style", logger), } }) diff --git a/src/Utilities/DynamicFieldsUtils.res b/src/Utilities/DynamicFieldsUtils.res index 34c9b7d..f4a77f9 100644 --- a/src/Utilities/DynamicFieldsUtils.res +++ b/src/Utilities/DynamicFieldsUtils.res @@ -685,24 +685,3 @@ let useSubmitCallback = () => { } }, (line1, line2, state, city, postalCode)) } - -let usePaymentMethodTypeFromList = (~list, ~paymentMethod, ~paymentMethodType) => { - React.useMemo(() => { - PaymentMethodsRecord.getPaymentMethodTypeFromList( - ~list, - ~paymentMethod, - ~paymentMethodType=PaymentUtils.getPaymentMethodName( - ~paymentMethodType=paymentMethod, - ~paymentMethodName=paymentMethodType, - ), - )->Option.getOr(PaymentMethodsRecord.defaultPaymentMethodType) - }, (list, paymentMethod, paymentMethodType)) -} - -let useAreAllRequiredFieldsPrefilled = (~list, ~paymentMethod, ~paymentMethodType) => { - let paymentMethodTypes = usePaymentMethodTypeFromList(~list, ~paymentMethod, ~paymentMethodType) - - paymentMethodTypes.required_fields->Array.reduce(true, (acc, requiredField) => { - acc && requiredField.value != "" - }) -} diff --git a/src/Utilities/PaymentHelpers.res b/src/Utilities/PaymentHelpers.res index 343ffc7..8e6fda5 100644 --- a/src/Utilities/PaymentHelpers.res +++ b/src/Utilities/PaymentHelpers.res @@ -186,11 +186,10 @@ let rec pollRetrievePaymentIntent = ( }) } -let retrieveStatus = (~headers, ~switchToCustomPod, pollID) => { +let retrieveStatus = (~headers, ~switchToCustomPod, pollID, logger) => { open Promise let endpoint = ApiEndpoint.getApiEndPoint() let uri = `${endpoint}/poll/status/${pollID}` - let logger = OrcaLogger.make() logApi( ~optLogger=Some(logger), ~url=uri, @@ -245,9 +244,17 @@ let retrieveStatus = (~headers, ~switchToCustomPod, pollID) => { }) } -let rec pollStatus = (~headers, ~switchToCustomPod, ~pollId, ~interval, ~count, ~returnUrl) => { +let rec pollStatus = ( + ~headers, + ~switchToCustomPod, + ~pollId, + ~interval, + ~count, + ~returnUrl, + ~logger, +) => { open Promise - retrieveStatus(~headers, ~switchToCustomPod, pollId) + retrieveStatus(~headers, ~switchToCustomPod, pollId, logger) ->then(json => { let dict = json->JSON.Decode.object->Option.getOr(Dict.make()) let status = dict->getString("status", "") @@ -268,6 +275,7 @@ let rec pollStatus = (~headers, ~switchToCustomPod, ~pollId, ~interval, ~count, ~interval, ~count=count - 1, ~returnUrl, + ~logger, ) }, ) @@ -277,7 +285,15 @@ let rec pollStatus = (~headers, ~switchToCustomPod, ~pollId, ~interval, ~count, }) ->catch(e => { Console.log2("Unable to retrieve payment due to following error", e) - pollStatus(~headers, ~switchToCustomPod, ~pollId, ~interval, ~count=count - 1, ~returnUrl) + pollStatus( + ~headers, + ~switchToCustomPod, + ~pollId, + ~interval, + ~count=count - 1, + ~returnUrl, + ~logger, + ) }) } diff --git a/src/Utilities/PaymentUtils.res b/src/Utilities/PaymentUtils.res index c99bd83..05fdad0 100644 --- a/src/Utilities/PaymentUtils.res +++ b/src/Utilities/PaymentUtils.res @@ -5,6 +5,7 @@ let paymentListLookupNew = ( ~showGooglePay, ~areAllGooglePayRequiredFieldsPrefilled, ~areAllApplePayRequiredFieldsPrefilled, + ~isShowPaypal, ) => { let pmList = list->PaymentMethodsRecord.buildFromPaymentList let walletsList = [] @@ -45,7 +46,9 @@ let paymentListLookupNew = ( if walletToBeDisplayedInTabs->Array.includes(item.paymentMethodName) { otherPaymentList->Array.push(item.paymentMethodName)->ignore } else if item.methodType == "wallet" { - walletsList->Array.push(item.paymentMethodName)->ignore + if item.paymentMethodName !== "paypal" || isShowPaypal { + walletsList->Array.push(item.paymentMethodName)->ignore + } } else if item.methodType == "bank_debit" { otherPaymentList->Array.push(item.paymentMethodName ++ "_debit")->ignore } else if item.methodType == "bank_transfer" { @@ -237,3 +240,90 @@ let appendedCustomerAcceptance = (~isGuestCustomer, ~paymentType, ~body) => { ? body->Array.concat([("customer_acceptance", PaymentBody.customerAcceptanceBody)]) : body } + +let usePaymentMethodTypeFromList = (~list, ~paymentMethod, ~paymentMethodType) => { + React.useMemo(() => { + PaymentMethodsRecord.getPaymentMethodTypeFromList( + ~list, + ~paymentMethod, + ~paymentMethodType=getPaymentMethodName( + ~paymentMethodType=paymentMethod, + ~paymentMethodName=paymentMethodType, + ), + )->Option.getOr(PaymentMethodsRecord.defaultPaymentMethodType) + }, (list, paymentMethod, paymentMethodType)) +} + +let useAreAllRequiredFieldsPrefilled = (~list, ~paymentMethod, ~paymentMethodType) => { + let paymentMethodTypes = usePaymentMethodTypeFromList(~list, ~paymentMethod, ~paymentMethodType) + + paymentMethodTypes.required_fields->Array.reduce(true, (acc, requiredField) => { + acc && requiredField.value != "" + }) +} + +let useGetPaymentMethodList = (~list, ~paymentOptions, ~paymentType) => { + open Utils + let methodslist = Recoil.useRecoilValueFromAtom(RecoilAtoms.list) + + let {showCardFormByDefault, paymentMethodOrder} = Recoil.useRecoilValueFromAtom( + RecoilAtoms.optionAtom, + ) + + let isApplePayReady = Recoil.useRecoilValueFromAtom(RecoilAtoms.isApplePayReady) + let isGooglePayReady = Recoil.useRecoilValueFromAtom(RecoilAtoms.isGooglePayReady) + let optionAtomValue = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom) + + let paymentOrder = paymentMethodOrder->getOptionalArr->removeDuplicate + + let areAllGooglePayRequiredFieldsPrefilled = useAreAllRequiredFieldsPrefilled( + ~list, + ~paymentMethod="wallet", + ~paymentMethodType="google_pay", + ) + + let areAllApplePayRequiredFieldsPrefilled = useAreAllRequiredFieldsPrefilled( + ~list, + ~paymentMethod="wallet", + ~paymentMethodType="apple_pay", + ) + + React.useMemo(() => { + switch methodslist { + | Loaded(paymentlist) => + let paymentOrder = + paymentOrder->Array.length > 0 ? paymentOrder : PaymentModeType.defaultOrder + let plist = paymentlist->getDictFromJson->PaymentMethodsRecord.itemToObjMapper + let (wallets, otherOptions) = + plist->paymentListLookupNew( + ~order=paymentOrder, + ~showApplePay=isApplePayReady, + ~showGooglePay=isGooglePayReady, + ~areAllGooglePayRequiredFieldsPrefilled, + ~areAllApplePayRequiredFieldsPrefilled, + ~isShowPaypal=optionAtomValue.wallets.payPal === Auto, + ) + ( + wallets->removeDuplicate->Utils.getWalletPaymentMethod(paymentType), + paymentOptions->Array.concat(otherOptions)->removeDuplicate, + otherOptions, + ) + | SemiLoaded => + showCardFormByDefault && checkPriorityList(paymentMethodOrder) + ? ([], ["card"], []) + : ([], [], []) + | _ => ([], [], []) + } + }, ( + methodslist, + paymentMethodOrder, + isApplePayReady, + isGooglePayReady, + areAllGooglePayRequiredFieldsPrefilled, + areAllApplePayRequiredFieldsPrefilled, + optionAtomValue.wallets.payPal, + paymentType, + paymentOrder, + paymentOptions, + )) +} diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res index c3b8a2d..7376519 100644 --- a/src/Utilities/Utils.res +++ b/src/Utilities/Utils.res @@ -1214,3 +1214,31 @@ let generateRandomString = length => { }) result.contents } + +let getWalletPaymentMethod = (wallets, paymentType: CardThemeType.mode) => { + switch paymentType { + | GooglePayElement => wallets->Array.filter(item => item === "google_pay") + | PayPalElement => wallets->Array.filter(item => item === "paypal") + | ApplePayElement => wallets->Array.filter(item => item === "apple_pay") + | _ => wallets + } +} + +let expressCheckoutComponents = ["googlePay", "payPal", "applePay", "paymentRequestButtons"] + +let componentsForPaymentElementCreate = ["payment"]->Array.concat(expressCheckoutComponents) + +let isComponentTypeForPaymentElementCreate = componentType => { + componentsForPaymentElementCreate->Array.includes(componentType) +} + +let walletElementPaymentType: array = [ + GooglePayElement, + PayPalElement, + ApplePayElement, + PaymentRequestButtonsElement, +] + +let isWalletElementPaymentType = (paymentType: CardThemeType.mode) => { + walletElementPaymentType->Array.includes(paymentType) +} diff --git a/src/WalletElement.res b/src/WalletElement.res new file mode 100644 index 0000000..1395cc8 --- /dev/null +++ b/src/WalletElement.res @@ -0,0 +1,41 @@ +@react.component +let make = (~paymentType) => { + let sessionsObj = Recoil.useRecoilValueFromAtom(RecoilAtoms.sessions) + let methodslist = Recoil.useRecoilValueFromAtom(RecoilAtoms.list) + let (sessions, setSessions) = React.useState(_ => Dict.make()->JSON.Encode.object) + let (walletOptions, setWalletOptions) = React.useState(_ => []) + + let (list, setList) = React.useState(_ => PaymentMethodsRecord.defaultList) + + let (walletList, _, _) = PaymentUtils.useGetPaymentMethodList( + ~list, + ~paymentOptions=[], + ~paymentType, + ) + + React.useEffect(() => { + switch methodslist { + | Loaded(paymentlist) => + let plist = paymentlist->Utils.getDictFromJson->PaymentMethodsRecord.itemToObjMapper + setWalletOptions(_ => walletList) + setList(_ => plist) + | _ => () + } + None + }, (methodslist, walletList)) + React.useEffect(() => { + switch sessionsObj { + | Loaded(ssn) => setSessions(_ => ssn) + | _ => () + } + None + }, [sessionsObj]) + + Array.length > 0}> +
+ + + +
+
+} diff --git a/src/orca-loader/Elements.res b/src/orca-loader/Elements.res index 5ea77b0..5a6d6e2 100644 --- a/src/orca-loader/Elements.res +++ b/src/orca-loader/Elements.res @@ -112,7 +112,7 @@ let make = ( ) }) - let fetchPaymentsList = mountedIframeRef => { + let fetchPaymentsList = (mountedIframeRef, componentType) => { let handlePaymentMethodsLoaded = (event: Types.event) => { let json = event.data->Identity.anyTypeToJson let dict = json->getDictFromJson @@ -159,10 +159,15 @@ let make = ( } } let msg = [("sendPaymentMethodsResponse", true->JSON.Encode.bool)]->Dict.fromArray - addSmartEventListener("message", handlePaymentMethodsLoaded, "onPaymentMethodsLoaded") + addSmartEventListener( + "message", + handlePaymentMethodsLoaded, + `onPaymentMethodsLoaded-${componentType}`, + ) preMountLoaderIframeDiv->Window.iframePostMessage(msg) } - let fetchCustomerPaymentMethods = (mountedIframeRef, disableSaveCards) => { + + let fetchCustomerPaymentMethods = (mountedIframeRef, disableSaveCards, componentType) => { if !disableSaveCards { let handleCustomerPaymentMethodsLoaded = (event: Types.event) => { let json = event.data->Identity.anyTypeToJson @@ -178,7 +183,7 @@ let make = ( addSmartEventListener( "message", handleCustomerPaymentMethodsLoaded, - "onCustomerPaymentMethodsLoaded", + `onCustomerPaymentMethodsLoaded-${componentType}`, ) } let msg = @@ -244,6 +249,10 @@ let make = ( | "cardNumber" | "cardExpiry" | "cardCvc" + | "googlePay" + | "payPal" + | "applePay" + | "paymentRequestButtons" | "payment" => () | str => manageErrorWarning(UNKNOWN_KEY, ~dynamicStr=`${str} type in create`, ~logger, ()) } @@ -267,7 +276,10 @@ let make = ( ->JSON.Encode.object let message = [ - ("paymentElementCreate", (componentType == "payment")->JSON.Encode.bool), + ( + "paymentElementCreate", + componentType->Utils.isComponentTypeForPaymentElementCreate->JSON.Encode.bool, + ), ("otherElements", otherElements->JSON.Encode.bool), ("options", newOptions), ("componentType", componentType->JSON.Encode.string), @@ -284,41 +296,53 @@ let make = ( ("launchTime", launchTime->JSON.Encode.float), ]->Dict.fromArray + let wallets = PaymentType.getWallets(newOptions->getDictFromJson, "wallets", logger) + let handleApplePayMounted = (event: Types.event) => { let json = event.data->anyTypeToJson let dict = json->getDictFromJson if dict->Dict.get("applePayMounted")->Option.isSome { - switch sessionForApplePay->Nullable.toOption { - | Some(session) => - try { - if session.canMakePayments() { - let msg = [("applePayCanMakePayments", true->JSON.Encode.bool)]->Dict.fromArray - mountedIframeRef->Window.iframePostMessage(msg) - } else { - Console.log("CANNOT MAKE PAYMENT USING APPLE PAY") - logger.setLogInfo( - ~value="CANNOT MAKE PAYMENT USING APPLE PAY", - ~eventName=APPLE_PAY_FLOW, - ~paymentMethod="APPLE_PAY", - ~logType=ERROR, - (), - ) - } - } catch { - | exn => { - let exnString = exn->anyTypeToJson->JSON.stringify - Console.log("CANNOT MAKE PAYMENT USING APPLE PAY: " ++ exnString) - logger.setLogInfo( - ~value=exnString, - ~eventName=APPLE_PAY_FLOW, - ~paymentMethod="APPLE_PAY", - ~logType=ERROR, - (), - ) + if wallets.applePay === Auto { + switch sessionForApplePay->Nullable.toOption { + | Some(session) => + try { + if session.canMakePayments() { + let msg = [("applePayCanMakePayments", true->JSON.Encode.bool)]->Dict.fromArray + mountedIframeRef->Window.iframePostMessage(msg) + } else { + Console.log("CANNOT MAKE PAYMENT USING APPLE PAY") + logger.setLogInfo( + ~value="CANNOT MAKE PAYMENT USING APPLE PAY", + ~eventName=APPLE_PAY_FLOW, + ~paymentMethod="APPLE_PAY", + ~logType=ERROR, + (), + ) + } + } catch { + | exn => { + let exnString = exn->anyTypeToJson->JSON.stringify + Console.log("CANNOT MAKE PAYMENT USING APPLE PAY: " ++ exnString) + logger.setLogInfo( + ~value=exnString, + ~eventName=APPLE_PAY_FLOW, + ~paymentMethod="APPLE_PAY", + ~logType=ERROR, + (), + ) + } } + | None => () } - | None => () + } else { + logger.setLogInfo( + ~value="ApplePay is set as 'never' by merchant", + ~eventName=APPLE_PAY_FLOW, + ~paymentMethod="APPLE_PAY", + ~logType=INFO, + (), + ) } } } @@ -593,6 +617,7 @@ let make = ( ~interval, ~count, ~returnUrl=url, + ~logger, ) ->then(_ => { PaymentHelpers.retrievePaymentIntent( @@ -677,7 +702,10 @@ let make = ( } ->then(res => { let (json, applePayPresent, googlePayPresent) = res - if componentType === "payment" && applePayPresent->Belt.Option.isSome { + if ( + componentType->Utils.isComponentTypeForPaymentElementCreate && + applePayPresent->Belt.Option.isSome + ) { //do operations here let processPayment = (token: JSON.t) => { //let body = PaymentBody.applePayBody(~token) @@ -776,7 +804,11 @@ let make = ( addSmartEventListener("message", handleApplePayMessages, "onApplePayMessages") } - if componentType === "payment" && googlePayPresent->Belt.Option.isSome { + if ( + componentType->Utils.isComponentTypeForPaymentElementCreate && + googlePayPresent->Belt.Option.isSome && + wallets.googlePay === Auto + ) { let dict = json->getDictFromJson let sessionObj = SessionsType.itemToObjMapper(dict, Others) let gPayToken = SessionsType.getPaymentSessionObj(sessionObj.sessionsToken, Gpay) @@ -888,6 +920,14 @@ let make = ( } catch { | _ => Console.log("Error loading Gpay") } + } else if wallets.googlePay === Never { + logger.setLogInfo( + ~value="GooglePay is set as never by merchant", + ~eventName=GOOGLE_PAY_FLOW, + ~paymentMethod="GOOGLE_PAY", + ~logType=INFO, + (), + ) } json->resolve @@ -901,18 +941,23 @@ let make = ( } } let msg = [("sendSessionTokensResponse", true->JSON.Encode.bool)]->Dict.fromArray - addSmartEventListener("message", handleSessionTokensLoaded, "onSessionTokensLoaded") + addSmartEventListener( + "message", + handleSessionTokensLoaded, + `onSessionTokensLoaded-${componentType}`, + ) preMountLoaderIframeDiv->Window.iframePostMessage(msg) } preMountLoaderMountedPromise ->then(_ => { - fetchPaymentsList(mountedIframeRef) + fetchPaymentsList(mountedIframeRef, componentType) if ( newOptions ->getDictFromJson - ->getBool("displaySavedPaymentMethods", true) + ->getBool("displaySavedPaymentMethods", true) && + !(Utils.expressCheckoutComponents->Array.includes(componentType)) ) { - fetchCustomerPaymentMethods(mountedIframeRef, false) + fetchCustomerPaymentMethods(mountedIframeRef, false, componentType) } fetchSessionTokens(mountedIframeRef) mountedIframeRef->Window.iframePostMessage(message) diff --git a/src/orca-loader/LoaderPaymentElement.res b/src/orca-loader/LoaderPaymentElement.res index 0e3e2cd..5acfaec 100644 --- a/src/orca-loader/LoaderPaymentElement.res +++ b/src/orca-loader/LoaderPaymentElement.res @@ -158,14 +158,9 @@ let make = (componentType, options, setIframeRef, iframeRef, mountPostMessage) = `#orca-payment-element-iframeRef-${localSelectorString}`, ) switch elem->Nullable.toOption { - | Some(ele) => - ele + | Some(ele) => ele ->Window.style - ->Window.setHeight( - `${iframeHeightRef.contents !== 0.0 - ? iframeHeightRef.contents->Belt.Float.toString - : "200"}px`, - ) + ->Window.setHeight(`${iframeHeightRef.contents->Float.toString}px`) | None => () } } @@ -293,10 +288,11 @@ let make = (componentType, options, setIframeRef, iframeRef, mountPostMessage) = let oElement = Window.querySelector(selector) let classesBase = optionsDict->getClasses("base") - let additionalIframeStyle = componentType->Utils.isOtherElements ? "height: 2rem;" : "" + let additionalIframeStyle = + componentType->Utils.isOtherElements ? "height: 2rem;" : "height: 0;" switch oElement->Nullable.toOption { | Some(elem) => { - let iframeDiv = `
+ let iframeDiv = `