+
children
,
)
diff --git a/src/libraries/Window.res b/src/libraries/Window.res
index 8a326afbb..738b74681 100644
--- a/src/libraries/Window.res
+++ b/src/libraries/Window.res
@@ -206,3 +206,23 @@ type boundingClient = {x: int, y: int, width: int, height: int}
type env = {apiBaseUrl?: string, sdkBaseUrl?: string}
@val @scope("window")
external env: env = "_env_"
+
+type searchParams = {set: (. string, string) => unit, get: (. string) => Js.Json.t}
+type url = {searchParams: searchParams, href: string}
+@new external urlSearch: string => url = "URL"
+
+@val @scope("document") external createElement: string => Dom.element = "createElement"
+
+type location = {replace: (. string) => unit, href: string}
+@val @scope("window") external location: location = "location"
+
+@set external elementSrc: (Dom.element, string) => unit = "src"
+@set external elementOnload: (Dom.element, unit => unit) => unit = "onload"
+@set external elementOnerror: (Dom.element, exn => unit) => unit = "onerror"
+
+type body
+
+@val @scope("document")
+external body: body = "body"
+
+@send external appendChild: (body, Dom.element) => unit = "appendChild"
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/HSwitchDemoAppPreview.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/HSwitchDemoAppPreview.res
new file mode 100644
index 000000000..8c89faf4a
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/HSwitchDemoAppPreview.res
@@ -0,0 +1,152 @@
+@react.component
+let make = (~isShowFilters, ~isShowTestCards, ~children=React.null) => {
+ let (shirtQuantity, setShirtQuantity) = React.useState(() => 1)
+ let (capQuantity, setCapQuantity) = React.useState(() => 2)
+ let isModalOpen = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.isModalOpen)
+
+ let renderSDK = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.renderSDK)
+ let theme = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme)
+ let isDesktop = HSwitchSDKUtils.getIsDesktop(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.size),
+ )
+
+ let themeColors = HSwitchSDKUtils.getThemeColorsFromTheme(theme)
+ let setSize = Recoil.useSetRecoilState(HSwitchRecoilAtoms.size)
+ let setIsMobileScreen = Recoil.useSetRecoilState(HSwitchRecoilAtoms.isMobileScreen)
+ let isMobileScreen = MatchMedia.useMatchMedia("(max-width: 1100px)")
+
+ let (amount, setAmount) = Recoil.useRecoilState(HSwitchRecoilAtoms.amount)
+
+ let mobileWrapperClass = "w-[336px] rounded-[48px] p-2 mx-auto h-[760px] shadow-websiteShadow"
+ let desktopWrapperClass = "rounded-[8px] shadow-websiteShadow"
+
+ let mobileHeaderWrapperClass = "relative h-full rounded-[40px] overflow-hidden bg-white shadow-mobileHeaderShadow"
+
+ React.useEffect1(() => {
+ if isMobileScreen {
+ setSize(._ => "Mobile")
+ setIsMobileScreen(._ => true)
+ } else {
+ setIsMobileScreen(._ => false)
+ }
+
+ None
+ }, [isMobileScreen])
+
+ React.useEffect2(() => {
+ setAmount(._ => HSwitchSDKUtils.amountToDisplay(~shirtQuantity, ~capQuantity))
+ None
+ }, (shirtQuantity, capQuantity))
+
+ let getMobileFrameButtonElement = className => {
+
+ }
+
+
+
+
+
+
+ {getMobileFrameButtonElement("left-0 top-[7.5rem] h-10 rounded-tl-md rounded-bl-md")}
+ {getMobileFrameButtonElement("left-0 top-48 h-16 rounded-tl-md rounded-bl-md")}
+ {getMobileFrameButtonElement("left-0 top-[17rem] h-16 rounded-tl-md rounded-bl-md")}
+ {getMobileFrameButtonElement("right-0 top-52 h-24 rounded-tr-md rounded-br-md")}
+
+
+
+
+
+
+
+
+
+
+
+
+ {React.string("Hyperswitch Demo Store")}
+
+
+ {React.string(isDesktop ? "Test Mode" : "Test")}
+
+
+
+
+
+
+
+ {React.string("Pay Hyperswitch")}
+
+
+ {React.string("US$")}
+ {React.string(amount)}
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/HSwitchSdkPreview.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/HSwitchSdkPreview.res
new file mode 100644
index 000000000..691ba3976
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/HSwitchSdkPreview.res
@@ -0,0 +1,48 @@
+@react.component
+let make = (~isShowFilters, ~isShowTestCards, ~children=React.null) => {
+ let renderSDK = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.renderSDK)
+ let theme = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme)
+ let isDesktop = HSwitchSDKUtils.getIsDesktop(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.size),
+ )
+ let setIsMobileScreen = Recoil.useSetRecoilState(HSwitchRecoilAtoms.isMobileScreen)
+ let isMobileScreen = MatchMedia.useMatchMedia("(max-width: 1100px)")
+
+ let themeColors = HSwitchSDKUtils.getThemeColorsFromTheme(theme)
+
+ let setSize = Recoil.useSetRecoilState(HSwitchRecoilAtoms.size)
+
+ React.useEffect1(() => {
+ if isMobileScreen {
+ setSize(._ => "Mobile")
+ setIsMobileScreen(._ => true)
+ } else {
+ setIsMobileScreen(._ => false)
+ }
+
+ None
+ }, [isMobileScreen])
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/HyperswitchSDK.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/HyperswitchSDK.res
new file mode 100644
index 000000000..bed3e3e0e
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/HyperswitchSDK.res
@@ -0,0 +1,100 @@
+open Promise
+
+@react.component
+let make = (~viewType) => {
+ let setViewType = Recoil.useSetRecoilState(HSwitchRecoilAtoms.viewType)
+ let amountToShow =
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.amount)
+ ->Belt.Float.fromString
+ ->Belt.Option.getWithDefault(100.0) *. 100.0
+ let amount = amountToShow->Belt.Int.fromFloat->Belt.Int.toString
+ let fetchApi = AuthHooks.useApiFetcher()
+ let (options, setOptions) = React.useState(_ => None)
+ let (selectedMenu, setSelectedMenu) = React.useState(_ => "")
+
+ let theme = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme)->Js.String2.toLowerCase
+ let customerLocation = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.customerLocation)
+ let currency = HSwitchSDKUtils.getCurrencyFromCustomerLocation(customerLocation)
+ let country = HSwitchSDKUtils.getCountryFromCustomerLocation(customerLocation)
+ let countryCode = country
+
+ let hyperSwitchToken = LocalStorage.getItem("login")->Js.Nullable.toOption
+ let fetchDetails = APIUtils.useGetMethod()
+ let (merchantPublishableKey, setPublishableAPIKey) = React.useState(_ => "")
+
+ let fetchMerchantInfo = async () => {
+ try {
+ let accountUrl = APIUtils.getURL(~entityName=MERCHANT_ACCOUNT, ~methodType=Get, ())
+ let merchantDetailsJSON = await fetchDetails(accountUrl)
+ let merchantDetails = merchantDetailsJSON->HSwitchMerchantAccountUtils.getMerchantDetails
+ setPublishableAPIKey(_ => merchantDetails.publishable_key)
+ } catch {
+ | Js.Exn.Error(e) =>
+ let _err = Js.Exn.message(e)->Belt.Option.getWithDefault("Failed to Fetch!")
+ }
+ }
+
+ React.useEffect0(() => {
+ fetchMerchantInfo()->ignore
+ setViewType(._ => viewType)
+ None
+ })
+
+ React.useEffect1(() => {
+ let body = HSwitchSDKUtils.getDefaultPayload(amount, currency, country, countryCode)
+
+ let headers = switch hyperSwitchToken {
+ | Some(key) =>
+ switch key {
+ | "" => [("Content-Type", "application/json"), ("api-key", HSwitchSDKUtils.defaultAPIKey)]
+ | key => [
+ ("Content-Type", "application/json"),
+ ("Api-Key", "hyperswitch"),
+ ("Authorization", `Bearer ${key}`),
+ ]
+ }
+ | None => [("Content-Type", "application/json"), ("api-key", HSwitchSDKUtils.defaultAPIKey)]
+ }
+
+ fetchApi(
+ HSwitchSDKUtils.backendEndpointUrl,
+ ~method_=Fetch.Post,
+ ~bodyStr=body->Js.Json.stringify,
+ ~headers=headers->Js.Dict.fromArray,
+ (),
+ )
+ ->then(resp => {
+ Fetch.Response.json(resp)
+ })
+ ->then(json => {
+ let clientSecret =
+ json
+ ->Js.Json.decodeObject
+ ->Belt.Option.flatMap(x => x->Js.Dict.get("client_secret"))
+ ->Belt.Option.flatMap(Js.Json.decodeString)
+ ->Belt.Option.getWithDefault("")
+ setOptions(_ => Some(HSwitchSDKUtils.getOptions(clientSecret, theme)))
+ json->resolve
+ })
+ ->ignore
+ None
+ }, [theme])
+
+ let hyperPromise = switch merchantPublishableKey {
+ | "" => HSwitchSDKUtils.loadHyper(HSwitchSDKUtils.defaultPublishableKey)
+ | key => HSwitchSDKUtils.loadHyper(key)
+ }
+
+
+ {switch options {
+ | Some(val) =>
+
+ | None => React.null
+ }}
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/UniversalHyperswitchSDK.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/UniversalHyperswitchSDK.res
new file mode 100644
index 000000000..cca3900b8
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/UniversalHyperswitchSDK.res
@@ -0,0 +1,63 @@
+open Window
+
+@react.component
+let make = () => {
+ let (viewType, setViewType) = React.useState(_ => HSwitchSDKUtils.DemoApp)
+ let (isShowFilters, setIsShowFilters) = React.useState(_ => true)
+ let (isShowTestCards, setIsShowTestCards) = React.useState(_ => true)
+
+ React.useEffect1(() => {
+ let windowUrl = urlSearch(location.href)
+
+ let paramViewType = windowUrl.searchParams.get(. "viewType")->Js.Json.decodeString
+ let paramIsShowFilters = windowUrl.searchParams.get(. "isShowFilters")->Js.Json.decodeString
+ let paramIsShowTestCards = windowUrl.searchParams.get(. "isShowTestCards")->Js.Json.decodeString
+
+ switch paramViewType {
+ | Some(val) =>
+ switch val->Js.String2.toLowerCase {
+ | "demoapp" => setViewType(_ => HSwitchSDKUtils.DemoApp)
+ | "sdkpreview" => setViewType(_ => HSwitchSDKUtils.SdkPreview)
+ | _ => setViewType(_ => HSwitchSDKUtils.DemoApp)
+ }
+ | None => ()
+ }
+
+ switch paramIsShowFilters {
+ | Some(val) =>
+ switch val->Js.String2.toLowerCase {
+ | "true" => setIsShowFilters(_ => true)
+ | "false" => setIsShowFilters(_ => false)
+ | _ => setIsShowFilters(_ => true)
+ }
+ | None => ()
+ }
+
+ switch paramIsShowTestCards {
+ | Some(val) =>
+ switch val->Js.String2.toLowerCase {
+ | "true" => setIsShowTestCards(_ => true)
+ | "false" => setIsShowTestCards(_ => false)
+ | _ => setIsShowTestCards(_ => true)
+ }
+ | None => ()
+ }
+
+ None
+ }, [location.href])
+
+
+
+ {switch viewType {
+ | HSwitchSDKUtils.DemoApp =>
+
+
+
+ | HSwitchSDKUtils.SdkPreview =>
+
+
+
+ }}
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchCardData.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchCardData.res
new file mode 100644
index 000000000..3c77b16db
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchCardData.res
@@ -0,0 +1,65 @@
+@val @scope(("navigator", "clipboard"))
+external writeText: string => unit = "writeText"
+
+@react.component
+let make = (~icon, ~label, ~number, ~color) => {
+ let (isCopied, setIsCopied) = React.useState(_ => false)
+
+ let handleIsCopied = () => {
+ setIsCopied(_ => true)
+ writeText(number)
+ }
+
+ let handleMouseLeave = () => {
+ setIsCopied(_ => false)
+ }
+
+ let cardClass = "flex min-h-[38px] justify-between items-center p-[10px] bg-white rounded-md cursor-pointer font-bold text-xs border border-solid border-[rgba(60,66,87,.12)] w-full mb-2 relative shadow-testCardsShadow"
+ let cardAfterClass = `after:opacity-0 after:content-['Copy'] after:absolute after:bg-[rgba(86,86,86,.85)] after:text-white after:font-bold after:text-sm after:h-full after:w-full after:-m-[10px] after:rounded-md after:flex after:justify-center after:items-center after:transition-opacity after:duration-150 after:ease-in-out`
+ let cardCopiedAfter = "hover:after:content-['Copied'] after:bg-no-repeat bgUrl"
+
+ let cardDotElement =
+
+
+ let css = ".bgPosition:hover::after {
+ background-position: 60px;
+ }
+ .bgUrl::after {
+ background-image: url('icons/hyperswitchSDK/tickMarkWhite.svg')
+ }
+ "
+
+ <>
+
+
+ >
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchCheckoutForm.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchCheckoutForm.res
new file mode 100644
index 000000000..c1a33a2d0
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchCheckoutForm.res
@@ -0,0 +1,154 @@
+open HSwitchSDKTypes
+open HSwitchTypes
+open Promise
+
+@react.component
+let make = (~customerPaymentMethods) => {
+ let hyper = useHyper()
+ let theme = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme)
+ let setPaymentStatus = Recoil.useSetRecoilState(HSwitchRecoilAtoms.paymentStatus)
+ let amountToShow = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.amount)
+
+ let (isPaymentProcessing, setIsPaymentProcessing) = React.useState(_ => false)
+ let (errorMsg, setErrorMsg) = React.useState(_ => None)
+
+ let layout = switch Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.layout) {
+ | "Tabs" => "tabs"
+ | "Accordion" => "accordion"
+ | "Spaced Accordion" => "spaced"
+ | _ => "tabs"
+ }
+
+ let themeColors = HSwitchSDKUtils.getThemeColorsFromTheme(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme),
+ )
+
+ let options = HSwitchSDKUtils.getOptionsPayload(customerPaymentMethods, layout, theme)
+
+ let handleFormSubmit = event => {
+ event->ReactEvent.Form.preventDefault
+ setIsPaymentProcessing(_ => true)
+
+ let confirmParams =
+ [
+ (
+ "confirmParams",
+ [("return_url", HSwitchSDKUtils.redirectUrl->Js.Json.string)]
+ ->Js.Dict.fromArray
+ ->Js.Json.object_,
+ ),
+ ]
+ ->Js.Dict.fromArray
+ ->Js.Json.object_
+
+ hyper.confirmPayment(confirmParams)
+ ->then(val => {
+ let resDict = val->Js.Json.decodeObject->Belt.Option.getWithDefault(Js.Dict.empty())
+ let status =
+ resDict
+ ->Js.Dict.get("status")
+ ->Belt.Option.flatMap(Js.Json.decodeString)
+ ->Belt.Option.getWithDefault("")
+
+ setIsPaymentProcessing(_ => false)
+ setPaymentStatus(._ => status)
+
+ resolve()
+ })
+ ->ignore
+ }
+
+ let css = `.spinner,
+ .spinner:before,
+ .spinner:after {
+ border-radius: 50%;
+ }
+
+ .spinner {
+ color: #ffffff;
+ font-size: 22px;
+ text-indent: -99999px;
+ margin: 0px auto;
+ position: relative;
+ width: 20px;
+ height: 20px;
+ box-shadow: inset 0 0 0 2px;
+ -webkit-transform: translateZ(0);
+ -ms-transform: translateZ(0);
+ transform: translateZ(0);
+ }
+
+ .spinner:before,
+ .spinner:after {
+ position: absolute;
+ content: '';
+ }
+
+ .spinner:before {
+ width: 10.4px;
+ height: 20.4px;
+ background: ${"rgb(25,37,82)"};
+ border-radius: 20.4px 0 0 20.4px;
+ top: -0.2px;
+ left: -0.2px;
+ -webkit-transform-origin: 10.4px 10.2px;
+ transform-origin: 10.4px 10.2px;
+ -webkit-animation: loading 2s infinite ease 1.5s;
+ animation: loading 2s infinite ease 1.5s;
+ }
+
+ .spinner:after {
+ width: 10.4px;
+ height: 10.2px;
+ background: ${"rgb(25,37,82)"};
+ border-radius: 0 10.2px 10.2px 0;
+ top: -0.1px;
+ left: 10.2px;
+ -webkit-transform-origin: 0px 10.2px;
+ transform-origin: 0px 10.2px;
+ -webkit-animation: loading 2s infinite ease;
+ animation: loading 2s infinite ease;
+ }
+
+ @keyframes loading {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+ }`
+
+ let errorDiv = error => {
+
{React.string(error)}
+ }
+
+ let errorHandlingClass = errorMsg->Belt.Option.isSome ? "mt-1" : "mt-4"
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchExtraFeatures.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchExtraFeatures.res
new file mode 100644
index 000000000..cc8393fb9
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchExtraFeatures.res
@@ -0,0 +1,30 @@
+@react.component
+let make = (~isShowFilters) => {
+ let isMobileScreen = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.isMobileScreen)
+
+
+
+
+
+ {React.string("Hyperswitch")}
+
+
+
+
{React.string("Explore Hyperswitch")}
+
+
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilterData.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilterData.res
new file mode 100644
index 000000000..6c97c73f2
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilterData.res
@@ -0,0 +1,33 @@
+type tabName = CustomerLocation | Size | Theme | Layout
+
+let getStringFromTabName = name => {
+ switch name {
+ | CustomerLocation => "Customer Location"
+ | Size => "Size"
+ | Theme => "Theme"
+ | Layout => "Layout"
+ }
+}
+
+let customerLocations = [
+ "United Arab Emirates (AED)",
+ "Australia (AUD)",
+ "Brazil (BRL)",
+ "China (CNY)",
+ "Germany (EUR)",
+ "United Kingdom (GBP)",
+ "Indonesia (IDR)",
+ "Japan (JPY)",
+ "Mexico (MXN)",
+ "Malaysia (MYR)",
+ "Poland (PLN)",
+ "Singapore (SGD)",
+ "Thailand (THB)",
+ "United States (USD)",
+]
+
+let sizes = ["Desktop", "Mobile"]
+
+let themes = ["Default", "Brutal", "Midnight", "Soft", "Charcoal"]
+
+let layouts = ["Tabs", "Accordion", "Spaced Accordion"]
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilterDropdown.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilterDropdown.res
new file mode 100644
index 000000000..80a0b600e
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilterDropdown.res
@@ -0,0 +1,63 @@
+@react.component
+let make = (
+ ~list,
+ ~selectedValue,
+ ~setSelectedValue,
+ ~showExtra,
+ ~extraTitle,
+ ~extraDesc,
+ ~extraWidth,
+ ~isShowFlag,
+) => {
+ let setRenderSDK = Recoil.useSetRecoilState(HSwitchRecoilAtoms.renderSDK)
+ let isDesktop = HSwitchSDKUtils.getIsDesktop(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.size),
+ )
+ let isMobileScreen = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.isMobileScreen)
+
+ let handleChange = name => {
+ setSelectedValue(._ => name)
+
+ setRenderSDK(._ => false)
+ let _ = Js.Global.setTimeout(() => {
+ setRenderSDK(._ => true)
+ }, 500)
+ }
+
+
+
+
+
+
+ {list
+ ->Js.Array2.map(name => {
+ let iconName = name->HSwitchSDKUtils.getCountryFromCustomerLocation->Js.String2.toLowerCase
+
+ })
+ ->React.array}
+
+
+
+
+
{React.string(extraTitle)}
+
+
{React.string(extraDesc)}
+
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilterTab.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilterTab.res
new file mode 100644
index 000000000..fa000167b
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilterTab.res
@@ -0,0 +1,104 @@
+open HSwitchRecoilAtoms
+
+@react.component
+let make = (~tabName: HSwitchFilterData.tabName) => {
+ let (isShowFilterDropdown, setIsShowFilterDropdown) = React.useState(_ => false)
+ let isMobileScreen = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.isMobileScreen)
+
+ let list = switch tabName {
+ | CustomerLocation => HSwitchFilterData.customerLocations
+ | Size => HSwitchFilterData.sizes
+ | Theme => HSwitchFilterData.themes
+ | Layout => HSwitchFilterData.layouts
+ }
+
+ let (selectedValue, setSelectedValue) = switch tabName {
+ | CustomerLocation => Recoil.useRecoilState(customerLocation)
+ | Size => Recoil.useRecoilState(size)
+ | Theme => Recoil.useRecoilState(theme)
+ | Layout => Recoil.useRecoilState(layout)
+ }
+
+ let showExtra = switch tabName {
+ | CustomerLocation
+ | Theme => true
+ | _ => false
+ }
+
+ let extraTitle = switch tabName {
+ | CustomerLocation => HSwitchSDKUtils.customerLocationExtraTitle
+ | Theme => HSwitchSDKUtils.themeExtraTitle
+ | _ => ""
+ }
+
+ let extraDesc = switch tabName {
+ | CustomerLocation => HSwitchSDKUtils.customerLocationExtraDesc
+ | Theme => HSwitchSDKUtils.themeExtraDesc
+ | _ => ""
+ }
+
+ let extraWidth = switch tabName {
+ | CustomerLocation => "250px"
+ | Theme => "185px"
+ | _ => "185px"
+ }
+
+ let isShowFlag = tabName === CustomerLocation
+ let isSize = tabName === Size
+
+ let iconName =
+ selectedValue->HSwitchSDKUtils.getCountryFromCustomerLocation->Js.String2.toLowerCase
+
+ let tabNameString = tabName->HSwitchFilterData.getStringFromTabName
+ let filterId = `filter-btn-${tabNameString->Js.String2.replace(" ", "_")}`
+
+ React.useLayoutEffect0(() => {
+ Window.addEventListener("click", ev => {
+ let targetId = ReactEvent.Mouse.target(ev)["id"]
+ if targetId !== filterId && targetId !== filterId->Js.String2.concat("-arrow") {
+ setIsShowFilterDropdown(_ => false)
+ }
+ })
+ Some(
+ () => {
+ Window.removeEventListener("click", ev => {
+ let targetId = ReactEvent.Mouse.target(ev)["id"]
+ if targetId !== filterId && targetId !== filterId->Js.String2.concat("-arrow") {
+ setIsShowFilterDropdown(_ => false)
+ }
+ })
+ },
+ )
+ })
+
+
+
+ {React.string(tabName->HSwitchFilterData.getStringFromTabName)}
+
+
{React.string("|")}
+
setIsShowFilterDropdown(_ => true)}>
+
+
+
+
+ Js.String2.toLowerCase}-hs`} className="mr-1" />
+
+ {React.string(selectedValue)}
+ Js.String2.concat("-arrow")}
+ name="arrow-down-hs"
+ size=9
+ className="ml-1 text-[#5d5d5d]"
+ />
+
+
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilters.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilters.res
new file mode 100644
index 000000000..33efd2b1b
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchFilters.res
@@ -0,0 +1,14 @@
+@react.component
+let make = () => {
+ let isMobileView = MatchMedia.useMatchMedia("(max-width: 830px)")
+
+
+
+
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchHeader.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchHeader.res
new file mode 100644
index 000000000..822f53178
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchHeader.res
@@ -0,0 +1,37 @@
+@react.component
+let make = () => {
+ let isDesktop = HSwitchSDKUtils.getIsDesktop(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.size),
+ )
+
+ let desktopHeaderClass = "rounded-lg py-[6px] px-3"
+
+ let mobileDomainClass = "p-4"
+ let desktopDomainClass = "bg-[rgba(236,242,247,.4)] rounded-xl"
+
+ let windowControlElement =
+
+
+
+
+ {windowControlElement}
+ {windowControlElement}
+ {windowControlElement}
+
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchModal.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchModal.res
new file mode 100644
index 000000000..3680a2ac3
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchModal.res
@@ -0,0 +1,54 @@
+@react.component
+let make = (~isModalOpen, ~setIsModalOpen, ~children) => {
+ let setIsGlobalModalOpen = Recoil.useSetRecoilState(HSwitchRecoilAtoms.isModalOpen)
+
+ let themeColors = HSwitchSDKUtils.getThemeColorsFromTheme(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme),
+ )
+ let isDesktop = HSwitchSDKUtils.getIsDesktop(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.size),
+ )
+
+ let handleModalClose = () => {
+ if !isDesktop {
+ setIsModalOpen(_ => false)
+ setIsGlobalModalOpen(._ => false)
+ }
+ }
+
+ React.useLayoutEffect0(() => {
+ Window.addEventListener("click", ev => {
+ let targetId = ReactEvent.Mouse.target(ev)["id"]
+ if targetId === "modal-wrapper" {
+ handleModalClose()
+ }
+ })
+ Some(
+ () => {
+ Window.addEventListener("click", ev => {
+ let targetId = ReactEvent.Mouse.target(ev)["id"]
+ if targetId === "modal-wrapper" {
+ handleModalClose()
+ }
+ })
+ },
+ )
+ })
+
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchPaymentCompletePopup.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchPaymentCompletePopup.res
new file mode 100644
index 000000000..3d37065ec
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchPaymentCompletePopup.res
@@ -0,0 +1,89 @@
+open Window
+
+@react.component
+let make = () => {
+ let (isModalOpen, setIsModalOpen) = React.useState(_ => false)
+ let (paymentStatus, setPaymentStatus) = React.useState(_ => "")
+ let (paymentMsg, setPaymentMsg) = React.useState(_ => "")
+ let (iconName, setIconName) = React.useState(_ => "")
+ let themeColors = HSwitchSDKUtils.getThemeColorsFromTheme(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme),
+ )
+ let paymentStatusState = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.paymentStatus)
+ let (isClicked, setIsClicked) = React.useState(_ => false)
+
+ React.useEffect1(() => {
+ let windowUrl = urlSearch(location.href)
+ let status = windowUrl.searchParams.get(. "status")->Js.Json.decodeString
+
+ let finalStatus =
+ status === None && paymentStatusState !== "" ? Some(paymentStatusState) : status
+
+ switch finalStatus {
+ | Some(val) => {
+ switch val {
+ | "succeeded" => {
+ setPaymentStatus(_ => val)
+ setPaymentMsg(_ => HSwitchSDKUtils.successPaymentMsg)
+ setIconName(_ => "circle-tick")
+ }
+ | "failed" =>
+ setPaymentStatus(_ => val)
+ setPaymentMsg(_ => HSwitchSDKUtils.failurePaymentMsg)
+ setIconName(_ => "circle-cross")
+ | _ => {
+ setPaymentStatus(_ => "processing")
+ setPaymentMsg(_ => HSwitchSDKUtils.processingPaymentMsg)
+ setIconName(_ => "circle-tick")
+ }
+ }
+ setIsModalOpen(_ => true)
+ }
+ | None => ()
+ }
+
+ None
+ }, [paymentStatusState])
+
+ let handleRedirect = () => {
+ if !isClicked {
+ setIsClicked(_ => true)
+ let url = urlSearch(HSwitchSDKUtils.redirectUrl)
+ location.replace(. url.href)
+ }
+ }
+
+ let redirectMsg = isClicked ? "Restarting Demo..." : "Restart Demo"
+
+
+
+
+
+
+ {React.string(`Payment ${paymentStatus}`)}
+
+
{React.string(paymentMsg)}
+
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchProduct.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchProduct.res
new file mode 100644
index 000000000..2698a46c1
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchProduct.res
@@ -0,0 +1,50 @@
+@react.component
+let make = (~productImg, ~productTitle, ~productAmount, ~productQuantity, ~setProductQuantity) => {
+ let setIsGlobalModalOpen = Recoil.useSetRecoilState(HSwitchRecoilAtoms.isModalOpen)
+ let (isModalOpen, setIsModalOpen) = React.useState(_ => false)
+
+ let theme = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme)
+ let themeColors = HSwitchSDKUtils.getThemeColorsFromTheme(theme)
+
+ let handleModalOpen = () => {
+ setIsModalOpen(_ => true)
+ setIsGlobalModalOpen(._ => true)
+ }
+
+
+
+
+
+
{React.string(productTitle)}
+
+ {React.string(
+ `US$ ${(productAmount *. productQuantity->Belt.Int.toFloat)
+ ->Js.Float.toFixedWithPrecision(~digits=2)}`,
+ )}
+
+
+
+
handleModalOpen()}>
+
{React.string(`Qty ${productQuantity->Belt.Int.toString}`)}
+
+
+
1}>
+
+ {React.string(`US $${productAmount->Js.Float.toFixedWithPrecision(~digits=2)} each`)}
+
+
+
+
+
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchSDK.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchSDK.res
new file mode 100644
index 000000000..095305712
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchSDK.res
@@ -0,0 +1,12 @@
+external objToJson: {..} => Js.Json.t = "%identity"
+
+open HSwitchSDKTypes
+
+@react.component
+let make = (~options, ~selectedMenu, ~customerPaymentMethods, ~hyperPromise) => {
+
+ objToJson} hyper={hyperPromise}>
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchTermsAndPrivacy.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchTermsAndPrivacy.res
new file mode 100644
index 000000000..36fcb4809
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchTermsAndPrivacy.res
@@ -0,0 +1,34 @@
+@react.component
+let make = (~className="") => {
+ let themeColors = HSwitchSDKUtils.getThemeColorsFromTheme(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme),
+ )
+ let isDesktop = HSwitchSDKUtils.getIsDesktop(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.size),
+ )
+
+ let aTagClassName = `mr-3 underline decoration-dotted decoration-[${themeColors.textSecondaryColor}] text-[${themeColors.textSecondaryColor}] text-xs cursor-pointer`
+
+ let css = `.desktopWrapperClass {
+ position: absolute;
+ bottom: 7%;
+ }`
+
+ <>
+
+
+ >
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchTestCards.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchTestCards.res
new file mode 100644
index 000000000..832aebd98
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchTestCards.res
@@ -0,0 +1,48 @@
+@react.component
+let make = () => {
+ let (isToggle, setIsToggle) = React.useState(_ => false)
+
+ let handleToggleClick = () => {
+ setIsToggle(prev => !prev)
+ }
+
+ React.useEffect0(() => {
+ handleToggleClick()
+ Js.Global.setTimeout(() => {
+ handleToggleClick()
+ }, 1500)->ignore
+ None
+ })
+
+
+
handleToggleClick()}>
+
+
+
{React.string("Test Cards")}
+
+
+
+
+
+
+
+
+
+ {React.string(HSwitchSDKUtils.testCardsInfo)}
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchUpdateProductQuantity.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchUpdateProductQuantity.res
new file mode 100644
index 000000000..e6dcb7fed
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchUpdateProductQuantity.res
@@ -0,0 +1,93 @@
+@react.component
+let make = (~setIsModalOpen, ~productQuantity, ~setProductQuantity) => {
+ let setIsGlobalModalOpen = Recoil.useSetRecoilState(HSwitchRecoilAtoms.isModalOpen)
+ let (quantity, setQuantity) = React.useState(_ => productQuantity)
+ let themeColors = HSwitchSDKUtils.getThemeColorsFromTheme(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme),
+ )
+
+ let handleClose = () => {
+ setIsModalOpen(_ => false)
+ setIsGlobalModalOpen(._ => false)
+ }
+
+ let handleDec = () => {
+ if quantity > 1 {
+ setQuantity(prev => prev - 1)
+ }
+ }
+
+ let handleInc = () => {
+ if quantity < 10 {
+ setQuantity(prev => prev + 1)
+ }
+ }
+
+ let handleChange = ev => {
+ let val = ReactEvent.Form.target(ev)["value"]
+ switch val->Belt.Int.fromString {
+ | Some(num) =>
+ if num > 0 && num <= 99 {
+ setQuantity(_ => num)
+ }
+ | None => ()
+ }
+ }
+
+ let handleUpdate = () => {
+ setProductQuantity(_ => quantity)
+ handleClose()
+ }
+
+ let counterBtnClass = "text-sm font-normal mx-[15px] p-[10px] rounded-[20px] text-center w-8 h-8 flex items-center justify-center cursor-pointer"
+
+ <>
+
+
+
+
+
+ {React.string("Update Quantity")}
+
+
+ {React.string("The Pure Set")}
+
+
+
+
handleClose()} />
+
+
+
+ Belt.Int.toString}
+ onChange={handleChange}
+ />
+
+
+
+ >
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchViewProducts.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchViewProducts.res
new file mode 100644
index 000000000..972107773
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/HSwitchViewProducts.res
@@ -0,0 +1,50 @@
+@react.component
+let make = (~shirtQuantity, ~setShirtQuantity, ~capQuantity, ~setCapQuantity) => {
+ let isDesktop = HSwitchSDKUtils.getIsDesktop(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.size),
+ )
+ let themeColors = HSwitchSDKUtils.getThemeColorsFromTheme(
+ Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme),
+ )
+
+ let totalAmount = HSwitchSDKUtils.getTotalAmount(~shirtQuantity, ~capQuantity)
+ let taxAmount = HSwitchSDKUtils.getTaxAmount(~shirtQuantity, ~capQuantity)
+ let amountToDisplay = HSwitchSDKUtils.amountToDisplay(~shirtQuantity, ~capQuantity)
+
+ let dividerElement =
+
+
+
+
+ {dividerElement}
+
+
{React.string("Subtotal")}
+
{React.string(`US$ ${totalAmount}`)}
+
+
+
{React.string("Tax")}
+
{React.string(`US$ ${taxAmount}`)}
+
+
+
{React.string("Shipping")}
+
{React.string(`Free`)}
+
+ {dividerElement}
+
+
{React.string("Total")}
+
{React.string(`US$ ${amountToDisplay}`)}
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/PoweredBy.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/PoweredBy.res
new file mode 100644
index 000000000..c820702e2
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/components/PoweredBy.res
@@ -0,0 +1,10 @@
+@react.component
+let make = (~className="pt-4") => {
+ let theme = Recoil.useRecoilValueFromAtom(HSwitchRecoilAtoms.theme)
+ let themeColors = HSwitchSDKUtils.getThemeColorsFromTheme(theme)
+
+
+
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/libraries/HyperSwitch/HSwitchSDKTypes.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/libraries/HyperSwitch/HSwitchSDKTypes.res
new file mode 100644
index 000000000..c67fba1e0
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/libraries/HyperSwitch/HSwitchSDKTypes.res
@@ -0,0 +1,40 @@
+open HSwitchTypes
+
+@module("@juspay-tech/hyper-js")
+external loadHyper: string => hyperPromise = "loadHyper"
+
+@module("@juspay-tech/react-hyper-js")
+external useHyper: unit => hyperType = "useHyper"
+
+module HyperElements = {
+ @module("@juspay-tech/react-hyper-js") @react.component
+ external make: (
+ ~options: Js.Json.t,
+ ~hyper: Js.Promise.t
,
+ ~children: React.element,
+ ) => React.element = "HyperElements"
+}
+
+module PaymentElement = {
+ @module("@juspay-tech/react-hyper-js") @react.component
+ external make: (~id: string, ~options: Js.Json.t) => React.element = "PaymentElement"
+}
+
+module CardWidget = {
+ @module("@juspay-tech/react-hyper-js") @react.component
+ external make: (~id: string, ~options: options2) => React.element = "CardWidget"
+}
+
+module ElementsTest = {
+ @module("@juspay-tech/react-hyper-js") @react.component
+ external make: (
+ ~options: optionsTest,
+ ~stripe: hyperPromise,
+ ~children: React.element,
+ ) => React.element = "Elements"
+}
+
+module PaymentElementTest = {
+ @module("@juspay-tech/react-hyper-js") @react.component
+ external make: (~id: string, ~options: options2) => React.element = "PaymentElement"
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/libraries/HyperSwitch/HSwitchTypes.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/libraries/HyperSwitch/HSwitchTypes.res
new file mode 100644
index 000000000..eecc00254
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/libraries/HyperSwitch/HSwitchTypes.res
@@ -0,0 +1,36 @@
+type hyperPromise
+type sdkType = ELEMENT | WIDGET
+type paymentStatus =
+ SUCCESS | INCOMPLETE | FAILED | LOADING | PROCESSING | CHECKCONFIGURATION | CUSTOMSTATE
+type confirmParamType = {return_url: string}
+type confirmPaymentObj = {confirmParams: confirmParamType}
+type appearanceType = {theme: string}
+type options
+type options2
+type options1
+type dataValueType
+type dataType = {
+ elementType: string,
+ complete: bool,
+ empty: bool,
+ collapsed: bool,
+ value: dataValueType,
+}
+type hyperType = {
+ clientSecret: string,
+ confirmPayment: Js.Json.t => Promise.t,
+ retrievePaymentIntent: string => Promise.t,
+ paymentRequest: Js.Json.t => Js.Json.t,
+}
+type appearanceTestType = {theme: string}
+type optionsTest = {
+ clientSecret: string,
+ appearance: appearanceTestType,
+ hideIcon: bool,
+}
+type country = {
+ isoAlpha3: string,
+ currency: string,
+ countryName: string,
+ isoAlpha2: string,
+}
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/utilities/HSwitchRecoilAtoms.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/utilities/HSwitchRecoilAtoms.res
new file mode 100644
index 000000000..e5a2720c2
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/utilities/HSwitchRecoilAtoms.res
@@ -0,0 +1,10 @@
+let amount = Recoil.atom(. "amount", "20000")
+let customerLocation = Recoil.atom(. "customerLocation", "United States (USD)")
+let size = Recoil.atom(. "size", "Desktop")
+let theme = Recoil.atom(. "theme", "Default")
+let layout = Recoil.atom(. "layout", "Tabs")
+let renderSDK = Recoil.atom(. "renderSDK", true)
+let isModalOpen = Recoil.atom(. "isModalOpen", false)
+let viewType = Recoil.atom(. "viewType", HSwitchSDKUtils.DemoApp)
+let isMobileScreen = Recoil.atom(. "isMobileScreen", false)
+let paymentStatus = Recoil.atom(. "paymentStatus", "")
diff --git a/src/screens/HyperSwitch/UniversalHyperswitchSDK/utilities/HSwitchSDKUtils.res b/src/screens/HyperSwitch/UniversalHyperswitchSDK/utilities/HSwitchSDKUtils.res
new file mode 100644
index 000000000..c13414355
--- /dev/null
+++ b/src/screens/HyperSwitch/UniversalHyperswitchSDK/utilities/HSwitchSDKUtils.res
@@ -0,0 +1,294 @@
+external objToJson: {..} => Js.Json.t = "%identity"
+@val @scope("window") external hyper: string => HSwitchTypes.hyperPromise = "Hyper"
+
+let loadHyper = str => {
+ Js.Promise.make((~resolve, ~reject) => {
+ let scriptURL = "https://beta.hyperswitch.io/v1/HyperLoader.js"
+ let script = Window.createElement("script")
+ script->Window.elementSrc(scriptURL)
+ script->Window.elementOnload(() => resolve(. hyper(str)))
+ script->Window.elementOnerror(err => {
+ reject(. err)
+ })
+ Window.body->Window.appendChild(script)
+ })
+}
+
+let getCurrencyFromCustomerLocation = customerLocation => {
+ customerLocation->Js.String2.slice(~from=-4, ~to_=-1)
+}
+
+let getCountryFromCustomerLocation = customerLocation => {
+ switch customerLocation {
+ | "Germany (EUR)" => "DE"
+ | _ => customerLocation->Js.String2.slice(~from=-4, ~to_=-2)
+ }
+}
+
+type themeColor = {
+ backgroundColor: string,
+ color: string,
+ hyperswitchHeaderColor: string,
+ payHeaderColor: string,
+ boxShadowClassForSDK: string,
+ textSecondaryColor: string,
+ tabLabelColor: string,
+ checkoutButtonClass: string,
+ checkoutButtonShimmerClass: string,
+ amountColor: string,
+ backgroundSecondaryClass: string,
+ modalBackgroundColor: string,
+ counterButtonClass: string,
+ plusIcon: string,
+ inputClass: string,
+ productBorderClass: string,
+ productDividerClass: string,
+}
+
+let defaultThemeColor = {
+ backgroundColor: "#fff",
+ color: "#000",
+ hyperswitchHeaderColor: "rgba(26,26,26,0.9)",
+ payHeaderColor: "rgba(26,26,26,0.6)",
+ boxShadowClassForSDK: "before:shadow-defaultBoxShadowClassForSDKShadow",
+ textSecondaryColor: "rgba(26,26,26,0.5)",
+ tabLabelColor: "",
+ checkoutButtonClass: "text-white border-none bg-[rgb(0,109,249)]",
+ checkoutButtonShimmerClass: "bg-default_theme_button_shimmer",
+ amountColor: "",
+ backgroundSecondaryClass: "bg-[rgba(26,26,26,0.05)]",
+ modalBackgroundColor: "#fff",
+ counterButtonClass: "bg-[rgba(0,0,0,0.03)] text-[rgba(26,26,26,0.6)]",
+ plusIcon: "plus",
+ inputClass: "border-none shadow-defaultModalInputShadow focus:border focus:border-solid focus:border-[#006df9] focus:shadow-defaultModalInputFocusShadow",
+ productBorderClass: "border-b-[rgba(26,26,26,0.1)]",
+ productDividerClass: "bg-[rgb(230,230,230)]",
+}
+
+let getThemeColorsFromTheme = theme => {
+ switch theme {
+ | "Default" => defaultThemeColor
+ | "Brutal" => {
+ ...defaultThemeColor,
+ hyperswitchHeaderColor: "rgba(0,0,0,0.9)",
+ payHeaderColor: "rgba(0,0,0,0.6)",
+ textSecondaryColor: "rgba(0,0,0,0.5)",
+ backgroundColor: "rgba(124,255,112,0.54)",
+ tabLabelColor: "#000000",
+ checkoutButtonClass: "shadow-brutalButtonShadow text-[#000000] border-[0.17em] border-solid border-black bg-[#f5fb1f] active:translate-x-[0.05em] active:translate-y-[0.05em] active:shadow-brutalButtonActiveShadow",
+ checkoutButtonShimmerClass: "bg-brutal_theme_button_shimmer",
+ backgroundSecondaryClass: "shadow-brutalButtonShadow border-[0.17em] border-solid border-black bg-white active:translate-x-[0.05em] active:translate-y-[0.05em] active:shadow-brutalButtonActiveShadow",
+ counterButtonClass: "border-[0.17em] border-solid border-black shadow-brutalButtonShadow text-black active:translate-x-[0.05em] active:translate-y-[0.05em] active:shadow-brutalButtonActiveShadow",
+ plusIcon: "plusBlack",
+ inputClass: "shadow-brutalModalInputShadow border-[0.1em] border-solid border-black focus:translate-x-[0.05em] focus:translate-y-[0.05em] focus:shadow-brutalModalInputFocusShadow",
+ productDividerClass: "bg-[rgb(86,97,134)]",
+ }
+ | "Midnight" => {
+ backgroundColor: "rgb(26, 31, 54)",
+ color: "#fff",
+ hyperswitchHeaderColor: "rgba(229,229,229,0.9)",
+ payHeaderColor: "rgba(229,229,229,0.6)",
+ boxShadowClassForSDK: "before:shadow-midnightBoxShadowClassForSDKShadow",
+ textSecondaryColor: "rgba(229,229,229,0.5)",
+ tabLabelColor: "#000000",
+ checkoutButtonClass: "bg-[#85d996]",
+ checkoutButtonShimmerClass: "bg-midnight_theme_button_shimmer",
+ amountColor: "#85d996",
+ backgroundSecondaryClass: "bg-[rgba(229,229,229,0.05)]",
+ modalBackgroundColor: "#30313d",
+ counterButtonClass: "bg-[rgba(255,255,255,0.03)] text-[rgb(229,229,229)]",
+ plusIcon: "plusWhite",
+ inputClass: "border border-solid border-[#424353] text-white bg-[rgb(48,49,61)] shadow-midnightModalInputShadow focus-visible:border focus-visible:border-solid focus-visible:border-[#85d996] focus-visible:shadow-midnightModalInputFocusShadow",
+ productBorderClass: "border-b-[rgba(229,229,229,0.1)]",
+ productDividerClass: "bg-[rgb(66,67,83)]",
+ }
+ | "Soft" => {
+ ...defaultThemeColor,
+ color: "rgb(224,224,224)",
+ hyperswitchHeaderColor: "rgba(224,224,224,0.9)",
+ payHeaderColor: "rgba(224,224,224,0.6)",
+ textSecondaryColor: "rgba(224,224,224,0.5)",
+ boxShadowClassForSDK: "before:shadow-midnightBoxShadowClassForSDKShadow",
+ backgroundColor: "rgb(62, 62, 62)",
+ checkoutButtonClass: "shadow-softButtonShadow text-[rgb(125,143,255)]",
+ checkoutButtonShimmerClass: "bg-soft_theme_button_shimmer",
+ amountColor: "#7d8fff",
+ backgroundSecondaryClass: "shadow-softButtonShadow",
+ modalBackgroundColor: "rgb(62, 62, 62)",
+ counterButtonClass: "shadow-softButtonShadow",
+ inputClass: "bg-[rgb(60,61,62)] text-[#e0e0e0] shadow-softModalInputShadow",
+ plusIcon: "plusWhite",
+ productDividerClass: "bg-[rgb(86,97,134)]",
+ }
+ | "Charcoal" => {
+ ...defaultThemeColor,
+ backgroundColor: "rgba(221, 216, 216, 0.07)",
+ checkoutButtonClass: "bg-black text-white",
+ checkoutButtonShimmerClass: "bg-charcoal_theme_button_shimmer",
+ inputClass: "border-none shadow-charcoalModalInputShadow focus:border focus:border-solid focus:border-black focus:shadow-charcoalModalInputFocusShadow",
+ productDividerClass: "bg-black",
+ }
+ | _ => defaultThemeColor
+ }
+}
+
+let getTextColorFromTheme = theme => {
+ switch theme {
+ | "Default" => "#000"
+ | "Brutal" => "#000"
+ | "Midnight" => "rgb(255, 255, 255)"
+ | "Soft"
+ | "Charcoal" => "rgba(221, 216, 216, 0.07)"
+ | _ => "#fff"
+ }
+}
+
+let getIsDesktop = size => {
+ size === "Desktop"
+}
+
+let getSizeIconFromSize = size => {
+ if getIsDesktop(size) {
+ "desktop"
+ } else {
+ "desktop"
+ }
+}
+
+let redirectUrl = "https://hyperswitch-demo-store.netlify.app"
+
+let hyperswitchDocsUrl = "https://hyperswitch.io/docs"
+let hyperswitchRegisterUrl = "https://app.hyperswitch.io/register"
+let hyperswitchTermsOfServiceUrl = "https://hyperswitch.io/terms-of-services"
+let hyperswitchPrivacyPolicyUrl = "https://hyperswitch.io/privacyPolicy"
+
+let successTestCardNumber = "4242424242424242"
+let authenticationTestCardNumber = "4000000000003220"
+let declineTestCardNumber = "4000000000000002"
+
+let testCardsInfo = "Click to copy the card number. Use any future expiration date and three-number CVC."
+
+let customerLocationExtraTitle = "Every country pays differently"
+let customerLocationExtraDesc = "The Payment Element supports 135+ currencies. Only a sample is shown here. Hyperswitch automatically reorders payment methods to increase potential conversion."
+let themeExtraTitle = "Customize it"
+let themeExtraDesc = "Create a theme to match your brand with the Appearance API."
+
+let websiteDomain = "checkout.hyperswitch.io"
+
+let successPaymentMsg = "After a successful payment, the customer returns to your website"
+let failurePaymentMsg = "After a failed payment, the customer returns to your website"
+let processingPaymentMsg = "If the payment status is processing, the customer will be redirected to your website and you will receive webhooks on the payment status"
+
+let getDefaultPayload = (amount, currency, country, countryCode) =>
+ {
+ "amount": amount->Belt.Int.fromString->Belt.Option.getWithDefault(20000),
+ "currency": currency,
+ "shipping": {
+ "address": {
+ "country": country,
+ "state": "test",
+ "zip": "571201",
+ "line1": "test line 1",
+ "city": "test city",
+ "first_name": "Bopanna",
+ "last_name": "MJ",
+ },
+ "phone": {
+ "number": "+918105528927",
+ "counrty_code": countryCode,
+ },
+ },
+ "order_details": [
+ {
+ "product_name": "Apple iphone 15",
+ "quantity": 1,
+ "amount": amount->Belt.Int.fromString->Belt.Option.getWithDefault(20000),
+ },
+ ],
+ "billing": {
+ "address": {
+ "country": country,
+ },
+ },
+ "authentication_type": "no_three_ds",
+ "customer_id": "Bopanna17",
+ }->objToJson
+
+let defaultAPIKey = ""
+let defaultPublishableKey = ""
+
+let getOptions = (clientSecret, theme) => {
+ {
+ "clientSecret": clientSecret,
+ "appearance": {
+ "theme": theme,
+ },
+ "fonts": [
+ {
+ "cssSrc": "https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700&display=swap",
+ },
+ {
+ "cssSrc": "https://fonts.googleapis.com/css2?family=Quicksand:wght@400;500;600;700&family=Qwitcher+Grypen:wght@400;700&display=swap",
+ },
+ {
+ "cssSrc": "https://fonts.googleapis.com/css2?family=Combo&display=swap",
+ },
+ ],
+ "locale": "",
+ "loader": "always",
+ }
+}
+
+let backendEndpointUrl = "https://sandbox.hyperswitch.io/payments"
+
+let getLayoutPayload = layout => {
+ {
+ "type": layout === "spaced" ? "accordion" : layout,
+ "defaultCollapsed": false,
+ "radios": true,
+ "spacedAccordionItems": layout === "spaced",
+ }
+}
+
+let getOptionsPayload = (customerPaymentMethods, layout, theme) => {
+ {
+ "customerPaymentMethods": customerPaymentMethods,
+ "layout": getLayoutPayload(layout),
+ "wallets": {
+ "walletReturnUrl": redirectUrl,
+ "applePay": "auto",
+ "googlePay": "auto",
+ "style": {
+ "theme": switch theme {
+ | "Default"
+ | "Charcoal" => "dark"
+ | _ => "light"
+ },
+ },
+ },
+ }->objToJson
+}
+
+type viewType = DemoApp | SdkPreview
+type sizeType = Mobile | Desktop
+
+let getTotalAmountFloat = (~shirtQuantity, ~capQuantity) => {
+ 65.00 *. shirtQuantity->Belt.Int.toFloat +. 32.00 *. capQuantity->Belt.Int.toFloat
+}
+
+let getTotalAmount = (~shirtQuantity, ~capQuantity) => {
+ getTotalAmountFloat(~shirtQuantity, ~capQuantity)->Js.Float.toFixedWithPrecision(~digits=2)
+}
+
+let getTaxAmountFloat = (~shirtQuantity, ~capQuantity) => {
+ getTotalAmountFloat(~shirtQuantity, ~capQuantity) *. 0.1
+}
+
+let getTaxAmount = (~shirtQuantity, ~capQuantity) => {
+ getTaxAmountFloat(~shirtQuantity, ~capQuantity)->Js.Float.toFixedWithPrecision(~digits=2)
+}
+
+let amountToDisplay = (~shirtQuantity, ~capQuantity) => {
+ (getTotalAmountFloat(~shirtQuantity, ~capQuantity) +.
+ getTaxAmountFloat(~shirtQuantity, ~capQuantity))->Js.Float.toFixedWithPrecision(~digits=2)
+}
diff --git a/src/screens/login/HSwitchLoginFlow/HyperSwitchAuthScreen.res b/src/screens/login/HSwitchLoginFlow/HyperSwitchAuthScreen.res
index ed749027e..5191c6090 100644
--- a/src/screens/login/HSwitchLoginFlow/HyperSwitchAuthScreen.res
+++ b/src/screens/login/HSwitchLoginFlow/HyperSwitchAuthScreen.res
@@ -92,7 +92,11 @@ let make = (~setAuthStatus: HyperSwitchAuthTypes.authStatus => unit) => {
| list{"register", ..._},
) => () // to prevent duplicate push
| (LoginWithPassword | LoginWithEmail, _) =>
- `${HSwitchGlobalVars.hyperSwitchFEPrefix}/login`->RescriptReactRouter.replace
+ let loginUrl = HSwitchGlobalVars.hyperSwitchFEPrefix->Js.String2.concat("/login")
+
+ (
+ url.search === "" ? loginUrl : loginUrl->Js.String2.concat(`?${url.search}`)
+ )->RescriptReactRouter.replace
| (SignUP, list{"register", ..._}) => () // to prevent duplicate push
| (SignUP, _) => "register"->RescriptReactRouter.push
| (ForgetPassword | ForgetPasswordEmailSent, list{"forget-password", ..._}) => () // to prevent duplicate push
diff --git a/tailwindHyperSwitch.config.js b/tailwindHyperSwitch.config.js
index 5a4b223e9..6f61314da 100644
--- a/tailwindHyperSwitch.config.js
+++ b/tailwindHyperSwitch.config.js
@@ -76,6 +76,7 @@ module.exports = {
},
animation: {
"spin-slow": "spin 3s linear infinite",
+ spin: "spin 1s linear infinite",
slideUp: "slideUp 200ms ease-out forwards",
fade: "fadeOut 1s ease-in-out forwards",
secondsOnes: "secondsOnes 10s 0s 18 reverse", // format keyframe, duration, delay, iteration-count, direction
@@ -92,6 +93,7 @@ module.exports = {
ripple: "ripple 10s ease-in-out",
horizontalShaking: "horizontalShaking 0.5s 1s",
horizontalShakingDelay: "horizontalShaking 0.5s 4s",
+ shimmerMove: "shimmerMove 3s infinite ease",
},
transitionDelay: {
12: "12000ms",
@@ -314,6 +316,17 @@ module.exports = {
},
"100%": { transform: "translateX(0%)" },
},
+ spin: {
+ "100%": { transform: "rotate(1turn)" },
+ },
+ shimmerMove: {
+ "0%": {
+ transform: "translateX(calc(150%*-1));",
+ },
+ "100%": {
+ transform: "translateX(150%)",
+ },
+ },
}),
fontSize: {
body: "1rem",
@@ -358,6 +371,7 @@ module.exports = {
850: "#151A1F",
900: "#333333",
950: "#212830",
+ mobile_frame: "#404040c9",
},
green: {
50: "#EFF4EF",
@@ -544,6 +558,29 @@ module.exports = {
"ardra-purple": "#7984E6",
statusArdra: "#E6A779",
statusCreated: "#5C6073",
+ "jb-black": {
+ DEFAULT: "#000000",
+ 50: "#F3F3F3",
+ 100: "#DADADA",
+ 200: "#C0C0C0",
+ 300: "#A8A8A8",
+ 400: "#909090",
+ 500: "#787878",
+ 600: "#626262",
+ 700: "#4C4C4C",
+ 800: "#373737",
+ 900: "#242424",
+ },
+ default_theme_button_shimmer:
+ "linear-gradient(to_right,rgba(0,109,249,0)_0%,rgb(43,136,255)_50%,rgba(0,109,249,0)_100%)",
+ brutal_theme_button_shimmer:
+ "linear-gradient(to_right,rgba(245,251,31,0)_0%,rgb(251,252,198)_50%,rgba(245,251,31,0)_100%)",
+ midnight_theme_button_shimmer:
+ "linear-gradient(to_right,rgba(133,217,150,0)_0%,rgb(176,222,185)_50%,rgba(133,217,150,0)_100%)",
+ soft_theme_button_shimmer:
+ "linear-gradient(to_right,rgba(62,62,62,0)_0%,rgb(70,70,70)_50%,rgba(62,62,62,0)_100%)",
+ charcoal_theme_button_shimmer:
+ "linear-gradient(to_right,rgba(0,0,0,0)_0%,rgb(70,70,70)_50%,rgba(0,0,0,0)_100%)",
},
fontSize: {
"fs-10": "10px",
@@ -575,6 +612,38 @@ module.exports = {
boxShadowMultiple:
"2px -2px 24px 0px rgba(0, 0, 0, 0.04), -2px 2px 24px 0px rgba(0, 0, 0, 0.02)",
homePageBoxShadow: "0px 2px 16px 2px rgba(51, 51, 51, 0.16)",
+ websiteShadow:
+ "0 20px 44px rgba(50, 50, 93, .12), 0 -1px 32px rgba(50, 50, 93, .06), 0 3px 12px rgba(0, 0, 0, .08)",
+ mobileHeaderShadow: "0 0 2px rgba(10, 37, 64, .1)",
+ mobileFrameShadow:
+ "0 20px 44px rgba(50, 50, 93, .12), 0 -1px 32px rgba(50, 50, 93, .06), 0 3px 12px rgba(0, 0, 0, .08), inset 0 -2px 5px rgba(10, 37, 64, .35)",
+ testCardsShadow:
+ "0 2px 5px rgba(60, 66, 87, .12), 0 1px 1px rgba(0, 0, 0, .08)",
+ filterDropdownShadow:
+ "0 0 0 1px rgba(136, 152, 170, .1), 0 15px 35px 0 rgba(49, 49, 93, .1), 0 5px 15px 0 rgba(0, 0, 0, .08)",
+ filterExtraShadow: "rgb(227, 232, 238) 0px 1px 0px 0px inset",
+ websiteHeaderShadow: "0 0.5px 0 #ecf2f7",
+ modalShadow:
+ "rgba(0,0,0,0.2)_0px_40px_100px_0px,rgba(0,0,0,0.03)_0px_6px_12px_0px",
+ defaultBoxShadowClassForSDKShadow: "rgba(0,0,0,0.18)_15px_0px_30px_0px",
+ midnightBoxShadowClassForSDKShadow:
+ "rgba(0,0,0,0.82)_15px_0px_30px_0px",
+ defaultModalInputShadow:
+ "rgb(224,224,224)_0px_0px_0px_1px,rgba(0,0,0,0.07)_0px_2px_4px_0px,rgba(0,0,0,0.05)_0px_1px_1.5px_0px",
+ defaultModalInputFocusShadow: "#006df94c_0px_0px_0px_3px",
+ brutalModalInputShadow: "0.12em_0.12em",
+ brutalModalInputFocusShadow: "0.02em_0.02em",
+ midnightModalInputShadow:
+ "0px_2px_4px_rgb(0,0,0,0.5),0px_1px_6px_rgba(0,0,0,0.25)",
+ midnightModalInputFocusShadow: "#85d9964c_0px_0p_0px_3px",
+ softModalInputShadow:
+ "inset_4px_4px_5px_#353637,inset_-4px_-3px_7px_#434445",
+ charcoalModalInputShadow:
+ "rgb(224,224,224)_0px_0px_0px_1px,rgba(0,0,0,0.07)_0px_2px_4px_0px,rgba(0,0,0,0.05)_0px_1px_1.5px_0px",
+ charcoalModalInputFocusShadow: "#0000004c_0px_0px_0px_3px",
+ brutalButtonShadow: "0.15em_0.15em",
+ brutalButtonActiveShadow: "0.02em_0.02em",
+ softButtonShadow: "4px_4px_5px_#353637,-4px_-4px_5px_#434445",
},
gridTemplateColumns: {
6: "repeat(6, minmax(0, 1fr))",