From bdd0fa3ffd5b4e0018109541323981c945a1ed4a Mon Sep 17 00:00:00 2001 From: ArushKapoorJuspay <121166031+ArushKapoorJuspay@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:10:17 +0530 Subject: [PATCH 1/6] feat: added Klarna as a one click widget (#420) --- src/CardUtils.res | 1 + src/Components/SurchargeUtils.res | 14 +- src/LoaderController.res | 1 + src/PaymentElement.res | 30 +--- src/Payments/ApplePay.res | 10 +- src/Payments/GPay.res | 2 +- src/Payments/KlarnaSDK.res | 167 ++++++++++++------- src/Payments/KlarnaSDKTypes.res | 45 +++++ src/Payments/PayPal.res | 2 +- src/Payments/PaymentRequestButtonElement.res | 16 +- src/Payments/PaypalSDK.res | 2 +- src/RenderPaymentMethods.res | 1 + src/Types/CardThemeType.res | 3 + src/Types/PaymentModeType.res | 6 +- src/Types/PaymentType.res | 46 ++++- src/Utilities/DynamicFieldsUtils.res | 95 ++++++++--- src/Utilities/PaymentUtils.res | 44 ++++- src/Utilities/RecoilAtoms.res | 2 + src/Utilities/Utils.res | 4 +- src/WalletElement.res | 6 +- src/orca-loader/Elements.res | 1 + 21 files changed, 361 insertions(+), 137 deletions(-) create mode 100644 src/Payments/KlarnaSDKTypes.res diff --git a/src/CardUtils.res b/src/CardUtils.res index d60723150..39a0441d6 100644 --- a/src/CardUtils.res +++ b/src/CardUtils.res @@ -361,6 +361,7 @@ let getCardBrandIcon = (cardType, paymentType) => { | GooglePayElement | PayPalElement | ApplePayElement + | KlarnaElement | ExpressCheckoutElement | NONE => diff --git a/src/Components/SurchargeUtils.res b/src/Components/SurchargeUtils.res index e6f2ebd71..54fbaae22 100644 --- a/src/Components/SurchargeUtils.res +++ b/src/Components/SurchargeUtils.res @@ -6,6 +6,7 @@ let oneClickWallets = [ {paymentMethodType: "apple_pay", displayName: "ApplePay"}, {paymentMethodType: "paypal", displayName: "Paypal"}, {paymentMethodType: "google_pay", displayName: "GooglePay"}, + {paymentMethodType: "klarna", displayName: "Klarna"}, ] type walletSurchargeDetails = { @@ -20,17 +21,18 @@ let useSurchargeDetailsForOneClickWallets = (~paymentMethodListValue) => { React.useMemo(() => { oneClickWallets->Array.reduce([], (acc, wallet) => { - let isWalletBtnRendered = switch wallet.paymentMethodType { - | "apple_pay" => areOneClickWalletsRendered.isApplePay - | "paypal" => areOneClickWalletsRendered.isPaypal - | "google_pay" => areOneClickWalletsRendered.isGooglePay - | _ => false + let (isWalletBtnRendered, paymentMethod) = switch wallet.paymentMethodType { + | "apple_pay" => (areOneClickWalletsRendered.isApplePay, "wallet") + | "paypal" => (areOneClickWalletsRendered.isPaypal, "wallet") + | "google_pay" => (areOneClickWalletsRendered.isGooglePay, "wallet") + | "klarna" => (areOneClickWalletsRendered.isKlarna, "pay_later") + | _ => (false, "") } if isWalletBtnRendered { let paymentMethodType = PaymentMethodsRecord.getPaymentMethodTypeFromList( ~paymentMethodListValue, - ~paymentMethod="wallet", + ~paymentMethod, ~paymentMethodType=wallet.paymentMethodType, )->Option.getOr(PaymentMethodsRecord.defaultPaymentMethodType) switch paymentMethodType.surcharge_details { diff --git a/src/LoaderController.res b/src/LoaderController.res index 530066a3c..a22245d5f 100644 --- a/src/LoaderController.res +++ b/src/LoaderController.res @@ -82,6 +82,7 @@ let make = (~children, ~paymentMode, ~setIntegrateErrorError, ~logger, ~initTime | GooglePayElement | PayPalElement | ApplePayElement + | KlarnaElement | ExpressCheckoutElement | Payment => { let paymentOptions = PaymentType.itemToObjMapper(optionsDict, logger) diff --git a/src/PaymentElement.res b/src/PaymentElement.res index d5f04ccee..ea40f6166 100644 --- a/src/PaymentElement.res +++ b/src/PaymentElement.res @@ -42,6 +42,8 @@ let make = (~cardProps, ~expiryProps, ~cvcProps, ~paymentType: CardThemeType.mod setLoadSavedCards: (savedCardsLoadState => savedCardsLoadState) => unit, ) = React.useState(_ => LoadingSavedCards) + let isKlarnaRedirectFlow = PaymentUtils.getIsKlarnaRedirectFlow(sessions) + React.useEffect(() => { switch (displaySavedPaymentMethods, customerPaymentMethods) { | (false, _) => { @@ -106,6 +108,7 @@ let make = (~cardProps, ~expiryProps, ~cvcProps, ~paymentType: CardThemeType.mod let (walletList, paymentOptionsList, actualList) = PaymentUtils.useGetPaymentMethodList( ~paymentOptions, ~paymentType, + ~sessions, ) React.useEffect(() => { @@ -225,9 +228,6 @@ let make = (~cardProps, ~expiryProps, ~cvcProps, ~paymentType: CardThemeType.mod let checkRenderOrComp = () => { walletOptions->Array.includes("paypal") || isShowOrPayUsing } - let dict = sessions->getDictFromJson - let sessionObj = SessionsType.itemToObjMapper(dict, Others) - let klarnaTokenObj = SessionsType.getPaymentSessionObj(sessionObj.sessionsToken, Klarna) let loader = () => { handlePostMessageEvents( @@ -243,25 +243,11 @@ let make = (~cardProps, ~expiryProps, ~cvcProps, ~paymentType: CardThemeType.mod {switch selectedOption->PaymentModeType.paymentMode { | Card => | Klarna => - - {switch klarnaTokenObj { - | OtherTokenOptional(optToken) => - switch optToken { - | Some(token) => - - - - | None => - - - - } - | _ => - - - - }} - + + + + + | ACHTransfer => diff --git a/src/Payments/ApplePay.res b/src/Payments/ApplePay.res index 2bd861ebd..3471ba4c6 100644 --- a/src/Payments/ApplePay.res +++ b/src/Payments/ApplePay.res @@ -346,9 +346,9 @@ let make = (~sessionObj: option) => { None }, (isApplePayReady, isInvokeSDKFlow, paymentExperience)) -
- - + +
+ {if showApplePayLoader {
@@ -362,8 +362,8 @@ let make = (~sessionObj: option) => { }} - -
+
+ } let default = make diff --git a/src/Payments/GPay.res b/src/Payments/GPay.res index aa3782079..b904b0456 100644 --- a/src/Payments/GPay.res +++ b/src/Payments/GPay.res @@ -144,7 +144,7 @@ let make = (~sessionObj: option, ~thirdPartySessionObj: opti }, (paymentMethodTypes, stateJson)) let (_, buttonType, _) = options.wallets.style.type_ - let (_, heightType, _) = options.wallets.style.height + let (_, heightType, _, _) = options.wallets.style.height let height = switch heightType { | GooglePay(val) => val | _ => 48 diff --git a/src/Payments/KlarnaSDK.res b/src/Payments/KlarnaSDK.res index 2acaf11dd..63fb85b43 100644 --- a/src/Payments/KlarnaSDK.res +++ b/src/Payments/KlarnaSDK.res @@ -1,71 +1,50 @@ open RecoilAtoms -type token = {client_token: string} -type loadType = { - container: option, - color_text: option, - payment_method_category: option, -} +open Utils +open Promise +open KlarnaSDKTypes -type res = { - approved: bool, - show_form: bool, - authorization_token: string, - finalize_required: bool, -} -type some = { - init: token => unit, - load: (loadType, res => unit) => unit, - authorize: (loadType, JSON.t, res => unit) => unit, - loadPaymentReview: (loadType, res => unit) => unit, -} - -@val external klarnaInit: some = "Klarna.Payments" +@val external klarnaInit: some = "Klarna.Payments.Buttons" @react.component let make = (~sessionObj: SessionsType.token) => { - open Utils + let url = RescriptReactRouter.useUrl() + let componentName = CardUtils.getQueryParamsDictforKey(url.search, "componentName") let loggerState = Recoil.useRecoilValueFromAtom(RecoilAtoms.loggerAtom) + let setIsShowOrPayUsing = Recoil.useSetRecoilState(RecoilAtoms.isShowOrPayUsing) + let {publishableKey, sdkHandleOneClickConfirmPayment} = Recoil.useRecoilValueFromAtom(keys) + let options = Recoil.useRecoilValueFromAtom(optionAtom) let intent = PaymentHelpers.usePaymentIntent(Some(loggerState), Other) let {iframeId} = Recoil.useRecoilValueFromAtom(keys) let status = CommonHooks.useScript("https://x.klarnacdn.net/kp/lib/v1/api.js") // Klarna SDK script let paymentMethodListValue = Recoil.useRecoilValueFromAtom(PaymentUtils.paymentMethodListValue) + let setAreOneClickWalletsRendered = Recoil.useSetRecoilState(areOneClickWalletsRendered) + let (stateJson, setStatesJson) = React.useState(_ => JSON.Encode.null) + + let (_, _, _, heightType) = options.wallets.style.height + let height = switch heightType { + | Klarna(val) => val + | _ => 48 + } + let handleCloseLoader = () => { Utils.handlePostMessage([("fullscreen", false->JSON.Encode.bool)]) } - let submitCallback = React.useCallback((ev: Window.event) => { - let json = ev.data->JSON.parseExn - let confirm = json->Utils.getDictFromJson->ConfirmType.itemToObjMapper - - if confirm.doSubmit { - Utils.handlePostMessage([ - ("fullscreen", true->JSON.Encode.bool), - ("param", "paymentloader"->JSON.Encode.string), - ("iframeId", iframeId->JSON.Encode.string), - ]) - klarnaInit.authorize( - { - container: None, - color_text: None, - payment_method_category: Some("klarna"), - }, - Dict.make()->JSON.Encode.object, - (res: res) => { - let (connectors, _) = - paymentMethodListValue->PaymentUtils.getConnectors(PayLater(Klarna(SDK))) - let body = PaymentBody.klarnaSDKbody(~token=res.authorization_token, ~connectors) - res.approved - ? intent(~bodyArr=body, ~confirmParam=confirm.confirmParams, ~handleUserError=false, ()) - : handleCloseLoader() - }, - ) - } - }, [status]) - useSubmitPaymentData(submitCallback) + let paymentMethodTypes = DynamicFieldsUtils.usePaymentMethodTypeFromList( + ~paymentMethodListValue, + ~paymentMethod="pay_later", + ~paymentMethodType="klarna", + ) + + PaymentUtils.useStatesJson(setStatesJson) React.useEffect(() => { - if status == "ready" { + if ( + status === "ready" && + stateJson !== JSON.Encode.null && + paymentMethodTypes !== PaymentMethodsRecord.defaultPaymentMethodType + ) { let klarnaWrapper = GooglePayType.getElementById(Utils.document, "klarna-payments") klarnaWrapper.innerHTML = "" klarnaInit.init({ @@ -74,24 +53,84 @@ let make = (~sessionObj: SessionsType.token) => { klarnaInit.load( { - container: Some("#klarna-payments"), - color_text: Some("#E51515"), - payment_method_category: Some("pay_later"), + container: "#klarna-payments", + theme: options.wallets.style.theme == Dark ? "default" : "outlined", + shape: "default", + on_click: authorize => { + makeOneClickHandlerPromise(sdkHandleOneClickConfirmPayment)->then( + result => { + let result = result->JSON.Decode.bool->Option.getOr(false) + if result { + Utils.handlePostMessage([ + ("fullscreen", true->JSON.Encode.bool), + ("param", "paymentloader"->JSON.Encode.string), + ("iframeId", iframeId->JSON.Encode.string), + ]) + authorize( + {collect_shipping_address: componentName->getIsExpressCheckoutComponent}, + Dict.make()->JSON.Encode.object, + (res: res) => { + let (connectors, _) = + paymentMethodListValue->PaymentUtils.getConnectors(PayLater(Klarna(SDK))) + + let shippingContact = + res.collected_shipping_address->Option.getOr( + defaultCollectedShippingAddress, + ) + + let requiredFieldsBody = DynamicFieldsUtils.getKlarnaRequiredFields( + ~shippingContact, + ~paymentMethodTypes, + ~statesList=stateJson, + ) + + let klarnaSDKBody = PaymentBody.klarnaSDKbody( + ~token=res.authorization_token, + ~connectors, + ) + + let body = { + klarnaSDKBody + ->getJsonFromArrayOfJson + ->flattenObject(true) + ->mergeTwoFlattenedJsonDicts(requiredFieldsBody) + ->getArrayOfTupleFromDict + } + + res.approved + ? intent( + ~bodyArr=body, + ~confirmParam={ + return_url: options.wallets.walletReturnUrl, + publishableKey, + }, + ~handleUserError=false, + (), + ) + : handleCloseLoader() + }, + ) + } + resolve() + }, + ) + }, }, - (_res: res) => { - handlePostMessageEvents(~complete=true, ~empty=false, ~paymentType="klarna", ~loggerState) + _ => { + setAreOneClickWalletsRendered( + prev => { + ...prev, + isKlarna: true, + }, + ) + setIsShowOrPayUsing(_ => true) }, ) } None - }, [status]) - - let bottomElement = -
-
- - -
+ }, (status, stateJson, paymentMethodTypes)) + +
Belt.Int.toString}px`} id="klarna-payments" className="w-full" /> } let default = make diff --git a/src/Payments/KlarnaSDKTypes.res b/src/Payments/KlarnaSDKTypes.res new file mode 100644 index 000000000..f8db1adf7 --- /dev/null +++ b/src/Payments/KlarnaSDKTypes.res @@ -0,0 +1,45 @@ +type token = {client_token: string} +type collected_shipping_address = { + city: string, + country: string, + email: string, + family_name: string, + given_name: string, + phone: string, + postal_code: string, + region: string, + street_address: string, +} +let defaultCollectedShippingAddress = { + city: "", + country: "", + email: "", + family_name: "", + given_name: "", + phone: "", + postal_code: "", + region: "", + street_address: "", +} + +type res = { + approved: bool, + show_form: bool, + authorization_token: string, + finalize_required: bool, + collected_shipping_address?: collected_shipping_address, +} +type authorizeAttributes = {collect_shipping_address: bool} +type authorize = (authorizeAttributes, JSON.t, res => unit) => unit +type loadType = { + container?: string, + color_text?: string, + payment_method_category?: string, + theme?: string, + shape?: string, + on_click?: authorize => Promise.t, +} +type some = { + init: token => unit, + load: (loadType, JSON.t => unit) => unit, +} diff --git a/src/Payments/PayPal.res b/src/Payments/PayPal.res index d82417def..35caa351a 100644 --- a/src/Payments/PayPal.res +++ b/src/Payments/PayPal.res @@ -24,7 +24,7 @@ let make = () => { | Paypal(val) => val->PaypalSDKTypes.getLabel | _ => Paypal->PaypalSDKTypes.getLabel } - let (_, _, heightType) = options.wallets.style.height + let (_, _, heightType, _) = options.wallets.style.height let height = switch heightType { | Paypal(val) => val | _ => 48 diff --git a/src/Payments/PaymentRequestButtonElement.res b/src/Payments/PaymentRequestButtonElement.res index 0c44ede94..aa8ac6b0a 100644 --- a/src/Payments/PaymentRequestButtonElement.res +++ b/src/Payments/PaymentRequestButtonElement.res @@ -1,4 +1,4 @@ -type wallet = GPayWallet | PaypalWallet | ApplePayWallet | NONE +type wallet = GPayWallet | PaypalWallet | ApplePayWallet | KlarnaWallet | NONE let paymentMode = str => { switch str { | "gpay" @@ -8,6 +8,7 @@ let paymentMode = str => { | "applepay" | "apple_pay" => ApplePayWallet + | "klarna" => KlarnaWallet | _ => NONE } } @@ -56,6 +57,8 @@ let make = (~sessions, ~walletOptions, ~paymentType) => { Gpay, ) + let klarnaTokenObj = SessionsType.getPaymentSessionObj(sessionObj.sessionsToken, Klarna) + let {clientSecret} = Recoil.useRecoilValueFromAtom(RecoilAtoms.keys)
@@ -97,6 +100,17 @@ let make = (~sessions, ~walletOptions, ~paymentType) => { | ApplePayTokenOptional(optToken) => | _ => React.null } + | KlarnaWallet => + + {switch klarnaTokenObj { + | OtherTokenOptional(optToken) => + switch optToken { + | Some(token) => + | None => React.null + } + | _ => React.null + }} + | NONE => React.null } diff --git a/src/Payments/PaypalSDK.res b/src/Payments/PaypalSDK.res index bb58dd951..c1df5c1ae 100644 --- a/src/Payments/PaypalSDK.res +++ b/src/Payments/PaypalSDK.res @@ -22,7 +22,7 @@ let make = (~sessionObj: SessionsType.token, ~paymentType: CardThemeType.mode) = let options = Recoil.useRecoilValueFromAtom(RecoilAtoms.optionAtom) let (_, _, buttonType) = options.wallets.style.type_ - let (_, _, heightType) = options.wallets.style.height + let (_, _, heightType, _) = options.wallets.style.height let buttonStyle = { layout: "vertical", color: options.wallets.style.theme == Outline diff --git a/src/RenderPaymentMethods.res b/src/RenderPaymentMethods.res index 960c0d720..1023c4881 100644 --- a/src/RenderPaymentMethods.res +++ b/src/RenderPaymentMethods.res @@ -82,6 +82,7 @@ let make = ( | GooglePayElement | PayPalElement | ApplePayElement + | KlarnaElement | ExpressCheckoutElement | Payment => { | "googlePay" => GooglePayElement | "payPal" => PayPalElement | "applePay" => ApplePayElement + | "klarna" => KlarnaElement | "expressCheckout" => ExpressCheckoutElement | _ => NONE } @@ -113,6 +115,7 @@ let getPaymentModeToStrMapper = val => { | GooglePayElement => "GooglePayElement" | PayPalElement => "PayPalElement" | ApplePayElement => "ApplePayElement" + | KlarnaElement => "KlarnaElement" | ExpressCheckoutElement => "ExpressCheckoutElement" | NONE => "None" } diff --git a/src/Types/PaymentModeType.res b/src/Types/PaymentModeType.res index c95ff75c6..14d29b396 100644 --- a/src/Types/PaymentModeType.res +++ b/src/Types/PaymentModeType.res @@ -49,6 +49,9 @@ let paymentMode = str => { let defaultOrder = [ "card", + "apple_pay", + "google_pay", + "paypal", "klarna", "affirm", "afterpay_clearpay", @@ -63,9 +66,6 @@ let defaultOrder = [ "giropay", "ideal", "eps", - "apple_pay", - "google_pay", - "paypal", "crypto", "bancontact_card", "boleto", diff --git a/src/Types/PaymentType.res b/src/Types/PaymentType.res index 2b00dc7c8..4bf8b4ac5 100644 --- a/src/Types/PaymentType.res +++ b/src/Types/PaymentType.res @@ -60,7 +60,7 @@ type terms = { usBankAccount: showTerms, } type buttonHeight = Default | Custom -type heightType = ApplePay(int) | GooglePay(int) | Paypal(int) +type heightType = ApplePay(int) | GooglePay(int) | Paypal(int) | Klarna(int) type googlePayStyleType = Default | Buy | Donate | Checkout | Subscribe | Book | Pay | Order type paypalStyleType = Paypal | Checkout | Buynow | Pay | Installment type applePayStyleType = @@ -86,13 +86,14 @@ type theme = Dark | Light | Outline type style = { type_: styleTypeArray, theme: theme, - height: (heightType, heightType, heightType), + height: (heightType, heightType, heightType, heightType), } type wallets = { walletReturnUrl: string, applePay: showType, googlePay: showType, payPal: showType, + klarna: showType, style: style, } type business = {name: string} @@ -253,13 +254,14 @@ let defaultFields = { let defaultStyle = { type_: (ApplePay(Default), GooglePay(Default), Paypal(Paypal)), theme: Light, - height: (ApplePay(48), GooglePay(48), Paypal(48)), + height: (ApplePay(48), GooglePay(48), Paypal(48), Klarna(48)), } let defaultWallets = { walletReturnUrl: "", applePay: Auto, googlePay: Auto, payPal: Auto, + klarna: Auto, style: defaultStyle, } let defaultBillingAddress = { @@ -713,6 +715,31 @@ let getPaypalHeight = (val, logger) => { : Paypal(val) val } +let getKlarnaHeight = (val, logger) => { + let val: heightType = + val < 40 + ? { + valueOutRangeWarning( + val, + "options.style.height", + "[40-60] - Klarna. Value set to min", + ~logger, + ) + Klarna(40) + } + : val > 60 + ? { + valueOutRangeWarning( + val, + "options.style.height", + "[40-60] - Paypal. Value set to max", + ~logger, + ) + Klarna(60) + } + : Klarna(val) + val +} let getTheme = (str, logger) => { switch str { | "outline" => Outline @@ -724,7 +751,12 @@ let getTheme = (str, logger) => { } } let getHeightArray = (val, logger) => { - (val->getApplePayHeight(logger), val->getGooglePayHeight(logger), val->getPaypalHeight(logger)) + ( + val->getApplePayHeight(logger), + val->getGooglePayHeight(logger), + val->getPaypalHeight(logger), + val->getKlarnaHeight(logger), + ) } let getStyle = (dict, str, logger) => { dict @@ -747,7 +779,7 @@ let getWallets = (dict, str, logger) => { ->Option.flatMap(JSON.Decode.object) ->Option.map(json => { unknownKeysWarning( - ["applePay", "googlePay", "style", "walletReturnUrl", "payPal"], + ["applePay", "googlePay", "style", "walletReturnUrl", "payPal", "klarna"], json, "options.wallets", ~logger, @@ -767,6 +799,10 @@ let getWallets = (dict, str, logger) => { "options.wallets.payPal", logger, ), + klarna: getWarningString(json, "klarna", "auto", ~logger)->getShowType( + "options.wallets.klarna", + logger, + ), style: getStyle(json, "style", logger), } }) diff --git a/src/Utilities/DynamicFieldsUtils.res b/src/Utilities/DynamicFieldsUtils.res index 207f95b2f..1a0e770fe 100644 --- a/src/Utilities/DynamicFieldsUtils.res +++ b/src/Utilities/DynamicFieldsUtils.res @@ -753,6 +753,36 @@ let removeRequiredFieldsDuplicates = ( requiredFields } +let getNameFromString = (name, requiredFieldsArr) => { + let nameArr = name->String.split(" ") + let nameArrLength = nameArr->Array.length + switch requiredFieldsArr->Array.get(requiredFieldsArr->Array.length - 1)->Option.getOr("") { + | "first_name" => { + let end = nameArrLength === 1 ? nameArrLength : nameArrLength - 1 + nameArr + ->Array.slice(~start=0, ~end) + ->Array.reduce("", (acc, item) => { + acc ++ " " ++ item + }) + } + | "last_name" => + if nameArrLength === 1 { + "" + } else { + nameArr->Array.get(nameArrLength - 1)->Option.getOr(name) + } + | _ => name + }->String.trim +} + +let getNameFromFirstAndLastName = (~firstName, ~lastName, ~requiredFieldsArr) => { + switch requiredFieldsArr->Array.get(requiredFieldsArr->Array.length - 1)->Option.getOr("") { + | "first_name" => firstName + | "last_name" => lastName + | _ => firstName->String.concatMany([" ", lastName]) + }->String.trim +} + let getApplePayRequiredFields = ( ~billingContact: ApplePayTypes.billingContact, ~shippingContact: ApplePayTypes.shippingContact, @@ -777,7 +807,11 @@ let getApplePayRequiredFields = ( let fieldVal = switch item.field_type { | FullName | BillingName => - getName(billingContact.givenName, billingContact.familyName) + getNameFromFirstAndLastName( + ~firstName=billingContact.givenName, + ~lastName=billingContact.familyName, + ~requiredFieldsArr, + ) | AddressLine1 => billingContact.addressLines->getAddressLine(0) | AddressLine2 => billingContact.addressLines->getAddressLine(1) | AddressCity => billingContact.locality @@ -816,28 +850,6 @@ let getApplePayRequiredFields = ( }) } -let getNameFromString = (name, requiredFieldsArr) => { - let nameArr = name->String.split(" ") - let nameArrLength = nameArr->Array.length - switch requiredFieldsArr->Array.get(requiredFieldsArr->Array.length - 1)->Option.getOr("") { - | "first_name" => { - let end = nameArrLength === 1 ? nameArrLength : nameArrLength - 1 - nameArr - ->Array.slice(~start=0, ~end) - ->Array.reduce("", (acc, item) => { - acc ++ " " ++ item - }) - } - | "last_name" => - if nameArrLength === 1 { - "" - } else { - nameArr->Array.get(nameArrLength - 1)->Option.getOr(name) - } - | _ => name - }->String.trim -} - let getGooglePayRequiredFields = ( ~billingContact: GooglePayType.billingContact, ~shippingContact: GooglePayType.billingContact, @@ -930,3 +942,40 @@ let getPaypalRequiredFields = ( acc }) } + +let getKlarnaRequiredFields = ( + ~shippingContact: KlarnaSDKTypes.collected_shipping_address, + ~paymentMethodTypes: PaymentMethodsRecord.paymentMethodTypes, + ~statesList, +) => { + paymentMethodTypes.required_fields->Array.reduce(Dict.make(), (acc, item) => { + let requiredFieldsArr = item.required_field->String.split(".") + + let fieldVal = switch item.field_type { + | ShippingName => + getNameFromFirstAndLastName( + ~firstName=shippingContact.given_name, + ~lastName=shippingContact.family_name, + ~requiredFieldsArr, + ) + | ShippingAddressLine1 => shippingContact.street_address + | ShippingAddressCity => shippingContact.city + | ShippingAddressState => { + let administrativeArea = shippingContact.region + let countryCode = shippingContact.country + Utils.getStateNameFromStateCodeAndCountry(statesList, administrativeArea, countryCode) + } + | ShippingAddressCountry(_) => shippingContact.country + | ShippingAddressPincode => shippingContact.postal_code + | Email => shippingContact.email + | PhoneNumber => shippingContact.phone + | _ => "" + } + + if fieldVal !== "" { + acc->Dict.set(item.required_field, fieldVal->JSON.Encode.string) + } + + acc + }) +} diff --git a/src/Utilities/PaymentUtils.res b/src/Utilities/PaymentUtils.res index 39d975692..f9b1a654c 100644 --- a/src/Utilities/PaymentUtils.res +++ b/src/Utilities/PaymentUtils.res @@ -4,6 +4,8 @@ let paymentListLookupNew = ( list: PaymentMethodsRecord.paymentMethodList, ~order, ~isShowPaypal, + ~isShowKlarnaOneClick, + ~isKlarnaRedirectFlow, ) => { let pmList = list->PaymentMethodsRecord.buildFromPaymentList let walletsList = [] @@ -40,6 +42,12 @@ let paymentListLookupNew = ( otherPaymentList->Array.push("card")->ignore } else if item.methodType == "reward" { otherPaymentList->Array.push(item.paymentMethodName)->ignore + } else if item.methodType == "pay_later" { + if item.paymentMethodName === "klarna" && !isKlarnaRedirectFlow && isShowKlarnaOneClick { + walletsList->Array.push(item.paymentMethodName)->ignore + } else { + otherPaymentList->Array.push(item.paymentMethodName)->ignore + } } else { otherPaymentList->Array.push(item.paymentMethodName)->ignore } @@ -257,7 +265,17 @@ let useAreAllRequiredFieldsPrefilled = ( }) } -let useGetPaymentMethodList = (~paymentOptions, ~paymentType) => { +let getIsKlarnaRedirectFlow = sessions => { + let dict = sessions->Utils.getDictFromJson + let sessionObj = SessionsType.itemToObjMapper(dict, Others) + let klarnaTokenObj = SessionsType.getPaymentSessionObj(sessionObj.sessionsToken, Klarna) + switch klarnaTokenObj { + | OtherTokenOptional(optToken) => optToken->Option.isNone + | _ => true + } +} + +let useGetPaymentMethodList = (~paymentOptions, ~paymentType, ~sessions) => { open Utils let methodslist = Recoil.useRecoilValueFromAtom(RecoilAtoms.paymentMethodList) @@ -268,6 +286,14 @@ let useGetPaymentMethodList = (~paymentOptions, ~paymentType) => { let paymentOrder = paymentMethodOrder->getOptionalArr->removeDuplicate + let isKlarnaRedirectFlow = getIsKlarnaRedirectFlow(sessions) + + let filterPaymentMethods = (paymentOptionsList: array, ~isKlarnaRedirectFlow) => { + paymentOptionsList->Array.filter(paymentOptionsName => + !(paymentOptionsName === "klarna" && !isKlarnaRedirectFlow) + ) + } + React.useMemo(() => { switch methodslist { | Loaded(paymentlist) => @@ -278,10 +304,15 @@ let useGetPaymentMethodList = (~paymentOptions, ~paymentType) => { plist->paymentListLookupNew( ~order=paymentOrder, ~isShowPaypal=optionAtomValue.wallets.payPal === Auto, + ~isShowKlarnaOneClick=optionAtomValue.wallets.klarna === Auto, + ~isKlarnaRedirectFlow, ) ( wallets->removeDuplicate->Utils.getWalletPaymentMethod(paymentType), - paymentOptions->Array.concat(otherOptions)->removeDuplicate, + paymentOptions + ->Array.concat(otherOptions) + ->removeDuplicate + ->filterPaymentMethods(~isKlarnaRedirectFlow), otherOptions, ) | SemiLoaded => @@ -290,7 +321,14 @@ let useGetPaymentMethodList = (~paymentOptions, ~paymentType) => { : ([], [], []) | _ => ([], [], []) } - }, (methodslist, paymentMethodOrder, optionAtomValue.wallets.payPal, paymentType)) + }, ( + methodslist, + paymentMethodOrder, + optionAtomValue.wallets.payPal, + optionAtomValue.wallets.klarna, + paymentType, + isKlarnaRedirectFlow, + )) } let useStatesJson = setStatesJson => { diff --git a/src/Utilities/RecoilAtoms.res b/src/Utilities/RecoilAtoms.res index e0014550a..40beb7a88 100644 --- a/src/Utilities/RecoilAtoms.res +++ b/src/Utilities/RecoilAtoms.res @@ -62,12 +62,14 @@ type areOneClickWalletsRendered = { isGooglePay: bool, isApplePay: bool, isPaypal: bool, + isKlarna: bool, } let defaultAreOneClickWalletsRendered = { isGooglePay: false, isApplePay: false, isPaypal: false, + isKlarna: false, } let areOneClickWalletsRendered = Recoil.atom( diff --git a/src/Utilities/Utils.res b/src/Utilities/Utils.res index 7bddcce44..b7714e427 100644 --- a/src/Utilities/Utils.res +++ b/src/Utilities/Utils.res @@ -1226,11 +1226,12 @@ let getWalletPaymentMethod = (wallets, paymentType: CardThemeType.mode) => { | GooglePayElement => wallets->Array.filter(item => item === "google_pay") | PayPalElement => wallets->Array.filter(item => item === "paypal") | ApplePayElement => wallets->Array.filter(item => item === "apple_pay") + | KlarnaElement => wallets->Array.filter(item => item === "klarna") | _ => wallets } } -let expressCheckoutComponents = ["googlePay", "payPal", "applePay", "expressCheckout"] +let expressCheckoutComponents = ["googlePay", "payPal", "applePay", "klarna", "expressCheckout"] let componentsForPaymentElementCreate = ["payment"]->Array.concat(expressCheckoutComponents) @@ -1246,6 +1247,7 @@ let walletElementPaymentType: array = [ GooglePayElement, PayPalElement, ApplePayElement, + KlarnaElement, ExpressCheckoutElement, ] diff --git a/src/WalletElement.res b/src/WalletElement.res index 3e22e8e3e..897286d7e 100644 --- a/src/WalletElement.res +++ b/src/WalletElement.res @@ -7,7 +7,11 @@ let make = (~paymentType) => { let setPaymentMethodListValue = Recoil.useSetRecoilState(PaymentUtils.paymentMethodListValue) - let (walletList, _, _) = PaymentUtils.useGetPaymentMethodList(~paymentOptions=[], ~paymentType) + let (walletList, _, _) = PaymentUtils.useGetPaymentMethodList( + ~paymentOptions=[], + ~paymentType, + ~sessions, + ) React.useEffect(() => { switch methodslist { diff --git a/src/orca-loader/Elements.res b/src/orca-loader/Elements.res index 91a528c7c..4142b429b 100644 --- a/src/orca-loader/Elements.res +++ b/src/orca-loader/Elements.res @@ -260,6 +260,7 @@ let make = ( | "googlePay" | "payPal" | "applePay" + | "klarna" | "expressCheckout" | "payment" => () | str => manageErrorWarning(UNKNOWN_KEY, ~dynamicStr=`${str} type in create`, ~logger, ()) From 6b4fbb75b663ccdb99450a2eabe4ae30fe0f5fa2 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 5 Jun 2024 11:41:54 +0000 Subject: [PATCH 2/6] chore(release): 0.60.0 [skip ci] # [0.60.0](https://github.com/juspay/hyperswitch-web/compare/v0.59.2...v0.60.0) (2024-06-05) ### Features * added Klarna as a one click widget ([#420](https://github.com/juspay/hyperswitch-web/issues/420)) ([bdd0fa3](https://github.com/juspay/hyperswitch-web/commit/bdd0fa3ffd5b4e0018109541323981c945a1ed4a)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e81f12cb7..e2cfdf951 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.60.0](https://github.com/juspay/hyperswitch-web/compare/v0.59.2...v0.60.0) (2024-06-05) + + +### Features + +* added Klarna as a one click widget ([#420](https://github.com/juspay/hyperswitch-web/issues/420)) ([bdd0fa3](https://github.com/juspay/hyperswitch-web/commit/bdd0fa3ffd5b4e0018109541323981c945a1ed4a)) + ## [0.59.2](https://github.com/juspay/hyperswitch-web/compare/v0.59.1...v0.59.2) (2024-06-04) diff --git a/package-lock.json b/package-lock.json index e3ab7373e..ecf78bded 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.59.2", + "version": "0.60.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.59.2", + "version": "0.60.0", "hasInstallScript": true, "dependencies": { "@aws-sdk/client-cloudfront": "^3.414.0", diff --git a/package.json b/package.json index 94989df99..95975e01a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.59.2", + "version": "0.60.0", "main": "index.js", "private": true, "dependencies": { From 107e914865a0b6a677663746689c6452287fae19 Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja Date: Fri, 7 Jun 2024 12:29:12 +0530 Subject: [PATCH 3/6] feat: self serve url in env (#425) --- Hyperswitch-React-Demo-App/.env | 1 + Hyperswitch-React-Demo-App/src/Payment.js | 8 +++++--- Hyperswitch-React-Demo-App/webpack.common.js | 6 ++---- README.md | 2 ++ 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Hyperswitch-React-Demo-App/.env b/Hyperswitch-React-Demo-App/.env index d2c398adf..22dbd4bfb 100644 --- a/Hyperswitch-React-Demo-App/.env +++ b/Hyperswitch-React-Demo-App/.env @@ -3,4 +3,5 @@ HYPERSWITCH_PUBLISHABLE_KEY= HYPERSWITCH_SECRET_KEY= HYPERSWITCH_SERVER_URL= HYPERSWITCH_CLIENT_URL= +SELF_SERVER_URL= diff --git a/Hyperswitch-React-Demo-App/src/Payment.js b/Hyperswitch-React-Demo-App/src/Payment.js index b2b104a2f..03a28b0db 100644 --- a/Hyperswitch-React-Demo-App/src/Payment.js +++ b/Hyperswitch-React-Demo-App/src/Payment.js @@ -1,3 +1,4 @@ +/* eslint-disable no-undef */ import { useEffect, useState } from "react"; import React from "react"; import { HyperElements } from "@juspay-tech/react-hyper-js"; @@ -8,10 +9,11 @@ function Payment() { const [clientSecret, setClientSecret] = useState(""); useEffect(() => { + let url = SELF_SERVER_URL === "" ? ENDPOINT : SELF_SERVER_URL; Promise.all([ - fetch(`${endPoint}/config`), - fetch(`${endPoint}/urls`), - fetch(`${endPoint}/create-payment-intent`), + fetch(`${url}/config`), + fetch(`${url}/urls`), + fetch(`${url}/create-payment-intent`), ]) .then((responses) => { return Promise.all(responses.map((response) => response.json())); diff --git a/Hyperswitch-React-Demo-App/webpack.common.js b/Hyperswitch-React-Demo-App/webpack.common.js index 0826c5cfc..f3d25d3ee 100644 --- a/Hyperswitch-React-Demo-App/webpack.common.js +++ b/Hyperswitch-React-Demo-App/webpack.common.js @@ -47,11 +47,9 @@ module.exports = (endpoint, publicPath = "auto") => { template: "./public/playgroundIndex.html", }), new webpack.DefinePlugin({ - endPoint: - typeof endpoint === "string" - ? JSON.stringify(endpoint) - : JSON.stringify(process.env.SELF_SERVER_URL), + ENDPOINT: JSON.stringify(endpoint), SCRIPT_SRC: JSON.stringify(process.env.HYPERSWITCH_CLIENT_URL), + SELF_SERVER_URL: JSON.stringify(process.env.SELF_SERVER_URL ?? ""), }), new BundleAnalyzerPlugin({ analyzerMode: "static", diff --git a/README.md b/README.md index 77477bae7..e592c72dd 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,8 @@ Before you start the local setup, you will need an understanding of few keys - - **`HYPERSWITCH_CLIENT_URL`:** The URL of your hosted Hyperswitch SDK. You can also use our Sandbox URL (https://beta.hyperswitch.io/v1) or specify your app running locally (e.g., http://localhost:9050). +- **`SELF_SERVER_URL`:** The URL of the hosted server file for generating client-secret and for fetching urls & configs. (eg: http://localhost:9060/payments) + ### About Env Configs for SDK - **`ENV_BACKEND_URL`:** Sets the endpoint for all the APIs used within the SDK to interact with the backend service. If you are running your own backend service, you can configure and specify its endpoint here for local setups. From c2cf5c822d4fe5d88f1070d6666b0a3fc0a8f6a7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 7 Jun 2024 07:01:49 +0000 Subject: [PATCH 4/6] chore(release): 0.61.0 [skip ci] # [0.61.0](https://github.com/juspay/hyperswitch-web/compare/v0.60.0...v0.61.0) (2024-06-07) ### Features * self serve url in env ([#425](https://github.com/juspay/hyperswitch-web/issues/425)) ([107e914](https://github.com/juspay/hyperswitch-web/commit/107e914865a0b6a677663746689c6452287fae19)) --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2cfdf951..e24054b00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [0.61.0](https://github.com/juspay/hyperswitch-web/compare/v0.60.0...v0.61.0) (2024-06-07) + + +### Features + +* self serve url in env ([#425](https://github.com/juspay/hyperswitch-web/issues/425)) ([107e914](https://github.com/juspay/hyperswitch-web/commit/107e914865a0b6a677663746689c6452287fae19)) + # [0.60.0](https://github.com/juspay/hyperswitch-web/compare/v0.59.2...v0.60.0) (2024-06-05) diff --git a/package-lock.json b/package-lock.json index ecf78bded..4c530b195 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.60.0", + "version": "0.61.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.60.0", + "version": "0.61.0", "hasInstallScript": true, "dependencies": { "@aws-sdk/client-cloudfront": "^3.414.0", diff --git a/package.json b/package.json index 95975e01a..6716a8dc7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.60.0", + "version": "0.61.0", "main": "index.js", "private": true, "dependencies": { From 844688be082208db21ebcc2d9e39e17bba71e96c Mon Sep 17 00:00:00 2001 From: Pritish Budhiraja Date: Fri, 7 Jun 2024 13:24:33 +0530 Subject: [PATCH 5/6] refactor: webpack readability and refactoring (#430) --- Hyperswitch-React-Demo-App/webpack.common.js | 10 +- Hyperswitch-React-Demo-App/webpack.dev.js | 13 +- webpack.common.js | 253 +++++++++---------- webpack.dev.js | 33 ++- 4 files changed, 140 insertions(+), 169 deletions(-) diff --git a/Hyperswitch-React-Demo-App/webpack.common.js b/Hyperswitch-React-Demo-App/webpack.common.js index f3d25d3ee..9b0f0039d 100644 --- a/Hyperswitch-React-Demo-App/webpack.common.js +++ b/Hyperswitch-React-Demo-App/webpack.common.js @@ -4,14 +4,14 @@ const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const CopyPlugin = require("copy-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const TerserPlugin = require("terser-webpack-plugin"); -const BundleAnalyzerPlugin = - require("webpack-bundle-analyzer").BundleAnalyzerPlugin; +const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); require("dotenv").config({ path: "./.env" }); module.exports = (endpoint, publicPath = "auto") => { - let entries = { + const entries = { app: "./src/index.js", }; + return { mode: "development", devtool: "source-map", @@ -37,9 +37,7 @@ module.exports = (endpoint, publicPath = "auto") => { new CopyPlugin({ patterns: [ { from: "public" }, - { - from: path.resolve(__dirname, "server.js"), - }, + { from: path.resolve(__dirname, "server.js") }, ], }), new HtmlWebpackPlugin({ diff --git a/Hyperswitch-React-Demo-App/webpack.dev.js b/Hyperswitch-React-Demo-App/webpack.dev.js index e950ece5b..3ae483540 100644 --- a/Hyperswitch-React-Demo-App/webpack.dev.js +++ b/Hyperswitch-React-Demo-App/webpack.dev.js @@ -2,7 +2,7 @@ const path = require("path"); const { merge } = require("webpack-merge"); const common = require("./webpack.common.js"); -let devServer = { +const devServer = { contentBase: path.join(__dirname, "dist"), hot: true, port: 9060, @@ -20,10 +20,7 @@ let devServer = { }, }; -module.exports = merge([ - common("/payments"), - { - mode: "development", - devServer: devServer, - }, -]); +module.exports = merge(common("/payments"), { + mode: "development", + devServer, +}); diff --git a/webpack.common.js b/webpack.common.js index ccea631e4..81f350aa7 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -6,158 +6,98 @@ const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const CopyPlugin = require("copy-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const TerserPlugin = require("terser-webpack-plugin"); -const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; +const BundleAnalyzerPlugin = + require("webpack-bundle-analyzer").BundleAnalyzerPlugin; const { sentryWebpackPlugin } = require("@sentry/webpack-plugin"); -const sdkEnv = process.env.sdkEnv ?? "local"; -const envSdkUrl = process.env.ENV_SDK_URL ?? ""; -const envBackendUrl = process.env.ENV_BACKEND_URL ?? ""; -const envLoggingUrl = process.env.ENV_LOGGING_URL ?? ""; +const getEnvVariable = (variable, defaultValue) => + process.env[variable] ?? defaultValue; -//git rev-parse --abbrev-ref HEAD -let repoVersion = require("./package.json").version; -let majorVersion = "v" + repoVersion.split(".")[0]; +const sdkEnv = getEnvVariable("sdkEnv", "local"); +const envSdkUrl = getEnvVariable("ENV_SDK_URL", ""); +const envBackendUrl = getEnvVariable("ENV_BACKEND_URL", ""); +const envLoggingUrl = getEnvVariable("ENV_LOGGING_URL", ""); -let repoName = require("./package.json").name; -let repoPublicPath = sdkEnv === "local" ? "" : `/${repoVersion}/${majorVersion}`; +const repoVersion = require("./package.json").version; +const majorVersion = "v" + repoVersion.split(".")[0]; +const repoName = require("./package.json").name; +const repoPublicPath = + sdkEnv === "local" ? "" : `/${repoVersion}/${majorVersion}`; -let sdkUrl; - -if (envSdkUrl.length === 0) { - sdkUrl = - sdkEnv === "prod" - ? "https://checkout.hyperswitch.io" - : sdkEnv === "sandbox" - ? "https://beta.hyperswitch.io" - : sdkEnv === "integ" - ? "https://dev.hyperswitch.io" - : "http://localhost:9050"; -} else { - sdkUrl = envSdkUrl; -} - -let backendEndPoint; -if (envBackendUrl.length === 0) { - backendEndPoint = - sdkEnv === "prod" - ? "https://checkout.hyperswitch.io/api" - : sdkEnv === "sandbox" - ? "https://beta.hyperswitch.io/api" - : sdkEnv === "integ" - ? "https://integ-api.hyperswitch.io" - : "https://beta.hyperswitch.io/api"; -} else { - backendEndPoint = envBackendUrl; -} - -let confirmEndPoint; -if (envBackendUrl.length === 0) { - confirmEndPoint = - sdkEnv === "prod" - ? "https://api.hyperswitch.io" - : sdkEnv === "sandbox" - ? "https://sandbox.hyperswitch.io" - : sdkEnv === "integ" - ? "https://integ-api.hyperswitch.io" - : "https://sandbox.hyperswitch.io"; -} else { - confirmEndPoint = envBackendUrl; -} - -let logEndpoint; -if (envLoggingUrl.length === 0) { - logEndpoint = - sdkEnv === "prod" - ? "https://api.hyperswitch.io/logs/sdk" - : "https://sandbox.hyperswitch.io/logs/sdk"; -} else { - logEndpoint = envLoggingUrl; -} - -// Set this to true to enable logging -let enableLogging = true; +const getSdkUrl = (env, customUrl) => { + if (customUrl) return customUrl; + const urls = { + prod: "https://checkout.hyperswitch.io", + sandbox: "https://beta.hyperswitch.io", + integ: "https://dev.hyperswitch.io", + local: "http://localhost:9050", + }; + return urls[env] || urls.local; +}; -// Choose from DEBUG, INFO, WARNING, ERROR, SILENT -let loggingLevel = "DEBUG"; +const sdkUrl = getSdkUrl(sdkEnv, envSdkUrl); +const backendEndPoint = + envBackendUrl || + `https://${sdkEnv === "prod" ? "checkout" : "beta"}.hyperswitch.io/api`; +const confirmEndPoint = + envBackendUrl || + `https://${sdkEnv === "prod" ? "api" : "sandbox"}.hyperswitch.io`; +const logEndpoint = + envLoggingUrl || + `https://${sdkEnv === "prod" ? "api" : "sandbox"}.hyperswitch.io/logs/sdk`; -// Maximum logs emitted for a particular event, to rate limit logs -let maxLogsPushedPerEventName = 100; +const enableLogging = true; +const loggingLevel = "DEBUG"; +const maxLogsPushedPerEventName = 100; module.exports = (publicPath = "auto") => { - let entries = { + const entries = { app: "./index.js", HyperLoader: "./src/orca-loader/HyperLoader.bs.js", }; - return { - mode: "development", - devtool: "source-map", - output: { - path: - sdkEnv && sdkEnv !== "local" - ? path.resolve(__dirname, "dist", sdkEnv) - : path.resolve(__dirname, "dist"), - clean: true, - publicPath: `${repoPublicPath}/`, - }, - // TODO - Can be commented for faster build in local development - optimization: { - sideEffects: true, - minimize: true, - minimizer: [ - new TerserPlugin({ - terserOptions: { - compress: { - drop_console: false, - }, - }, - }), - // For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line - // `...`, - // new CssMinimizerPlugin(), - ], - }, - plugins: [ - new MiniCssExtractPlugin(), - new CopyPlugin({ - patterns: [{ from: "public" }], - }), - new webpack.DefinePlugin({ - repoName: JSON.stringify(repoName), - repoVersion: JSON.stringify(repoVersion), - publicPath: JSON.stringify(repoPublicPath), - sdkUrl: JSON.stringify(sdkUrl), - backendEndPoint: JSON.stringify(backendEndPoint), - confirmEndPoint: JSON.stringify(confirmEndPoint), - logEndpoint: JSON.stringify(logEndpoint), - sentryDSN: JSON.stringify(process.env.SENTRY_DSN), - sentryScriptUrl: JSON.stringify(process.env.SENTRY_SCRIPT_URL), - enableLogging: JSON.stringify(enableLogging), - loggingLevel: JSON.stringify(loggingLevel), - maxLogsPushedPerEventName: JSON.stringify(maxLogsPushedPerEventName), - }), - new HtmlWebpackPlugin({ - inject: false, - template: "./public/build.html", - }), - new HtmlWebpackPlugin({ - inject: false, - template: "./public/build.html", - }), - new HtmlWebpackPlugin({ - // Also generate a test.html - inject: false, - filename: "fullscreenIndex.html", - template: "./public/fullscreenIndexTemplate.html", - }), + const plugins = [ + new MiniCssExtractPlugin(), + new CopyPlugin({ + patterns: [{ from: "public" }], + }), + new webpack.DefinePlugin({ + repoName: JSON.stringify(repoName), + repoVersion: JSON.stringify(repoVersion), + publicPath: JSON.stringify(repoPublicPath), + sdkUrl: JSON.stringify(sdkUrl), + backendEndPoint: JSON.stringify(backendEndPoint), + confirmEndPoint: JSON.stringify(confirmEndPoint), + logEndpoint: JSON.stringify(logEndpoint), + sentryDSN: JSON.stringify(process.env.SENTRY_DSN), + sentryScriptUrl: JSON.stringify(process.env.SENTRY_SCRIPT_URL), + enableLogging: JSON.stringify(enableLogging), + loggingLevel: JSON.stringify(loggingLevel), + maxLogsPushedPerEventName: JSON.stringify(maxLogsPushedPerEventName), + }), + new HtmlWebpackPlugin({ + inject: false, + template: "./public/build.html", + }), + new HtmlWebpackPlugin({ + // Also generate a test.html + inject: false, + filename: "fullscreenIndex.html", + template: "./public/fullscreenIndexTemplate.html", + }), + ]; + + if (process.env.NODE_ENV === "production") { + plugins.push( new BundleAnalyzerPlugin({ analyzerMode: "static", reportFilename: "bundle-report.html", openAnalyzer: false, - }), - // new webpack.HTMLInjectPlugin({ - // publicPath: JSON.stringify(repoVersion), - // }), - // TODO - Can be commented if sentry not needed. + }) + ); + } + + if (process.env.SENTRY_AUTH_TOKEN) { + plugins.push( sentryWebpackPlugin({ org: "sentry", project: "hyperswitch-react-sdk", @@ -169,8 +109,38 @@ module.exports = (publicPath = "auto") => { paths: ["dist"], }, }, - }), - ], + }) + ); + } + + return { + mode: sdkEnv === "local" ? "development" : "production", + devtool: sdkEnv === "local" ? "eval-source-map" : "source-map", + output: { + path: + sdkEnv && sdkEnv !== "local" + ? path.resolve(__dirname, "dist", sdkEnv) + : path.resolve(__dirname, "dist"), + clean: true, + publicPath: `${repoPublicPath}/`, + }, + optimization: + sdkEnv === "local" + ? {} + : { + sideEffects: true, + minimize: true, + minimizer: [ + new TerserPlugin({ + terserOptions: { + compress: { + drop_console: false, + }, + }, + }), + ], + }, + plugins, module: { rules: [ { @@ -188,6 +158,13 @@ module.exports = (publicPath = "auto") => { }, ], }, + { + test: /\.js$/, + exclude: /node_modules/, + use: { + loader: "babel-loader", + }, + }, ], }, entry: entries, diff --git a/webpack.dev.js b/webpack.dev.js index 993c77a9d..2104c3bcf 100644 --- a/webpack.dev.js +++ b/webpack.dev.js @@ -1,19 +1,20 @@ const path = require("path"); -const dotenv = require("dotenv").config(); +require("dotenv").config(); const { merge } = require("webpack-merge"); const common = require("./webpack.common.js"); + const sdkEnv = process.env.sdkEnv ?? "local"; -let backendEndPoint = - sdkEnv === "prod" - ? "https://api.hyperswitch.io/payments" - : sdkEnv === "sandbox" - ? "https://sandbox.hyperswitch.io/payments" - : sdkEnv === "integ" - ? "https://integ-api.hyperswitch.io/payments" - : "https://sandbox.hyperswitch.io/payments"; +const endpointMap = { + prod: "https://api.hyperswitch.io/payments", + sandbox: "https://sandbox.hyperswitch.io/payments", + integ: "https://integ-api.hyperswitch.io/payments", + local: "https://sandbox.hyperswitch.io/payments", // Default or local environment endpoint +}; + +const backendEndPoint = endpointMap[sdkEnv] || endpointMap.local; -let devServer = { +const devServer = { contentBase: path.join(__dirname, "dist"), hot: true, host: "0.0.0.0", @@ -26,6 +27,7 @@ let devServer = { secure: true, pathRewrite: { "^/payments": "" }, }, + // * Uncomment the following if needed for 3DS method proxying // "/3dsmethod": { // target: "https://acs40.sandbox.3dsecure.io", // changeOrigin: true, @@ -37,10 +39,7 @@ let devServer = { }, }; -module.exports = merge([ - common(), - { - mode: "development", - devServer: devServer, - }, -]); +module.exports = merge(common(), { + mode: "development", + devServer, +}); From 80f7393346a1cff67949388b3621e3e4017fef05 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 7 Jun 2024 07:56:08 +0000 Subject: [PATCH 6/6] chore(release): 0.61.1 [skip ci] ## [0.61.1](https://github.com/juspay/hyperswitch-web/compare/v0.61.0...v0.61.1) (2024-06-07) --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e24054b00..1e6dc95bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [0.61.1](https://github.com/juspay/hyperswitch-web/compare/v0.61.0...v0.61.1) (2024-06-07) + # [0.61.0](https://github.com/juspay/hyperswitch-web/compare/v0.60.0...v0.61.0) (2024-06-07) diff --git a/package-lock.json b/package-lock.json index 4c530b195..475a2c172 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orca-payment-page", - "version": "0.61.0", + "version": "0.61.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "orca-payment-page", - "version": "0.61.0", + "version": "0.61.1", "hasInstallScript": true, "dependencies": { "@aws-sdk/client-cloudfront": "^3.414.0", diff --git a/package.json b/package.json index 6716a8dc7..c1c4dc087 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orca-payment-page", - "version": "0.61.0", + "version": "0.61.1", "main": "index.js", "private": true, "dependencies": {