Skip to content

Commit

Permalink
Merge pull request #101 from Nosto/extract-client-script-to-hook
Browse files Browse the repository at this point in the history
NostoProvider: Extract client script loading functionality to a hook
  • Loading branch information
nosto-mikpou authored Aug 15, 2024
2 parents d235ee4 + 9d365c1 commit 6401719
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 77 deletions.
81 changes: 5 additions & 76 deletions src/components/NostoProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, isValidElement } from "react"
import { isValidElement } from "react"
import { NostoContext, RecommendationComponent } from "../context"
import { NostoClient } from "../types"
import { isNostoLoaded } from "./helpers"
import { useLoadClientScript } from "../hooks"
import type { ReactElement } from "react"

/**
* @group Components
Expand All @@ -22,7 +22,7 @@ export interface NostoProviderProps {
/**
* children
*/
children: React.ReactElement | React.ReactElement[]
children: ReactElement | ReactElement[]
/**
* Indicates if merchant uses multiple currencies
*/
Expand Down Expand Up @@ -65,88 +65,17 @@ export default function NostoProvider(props: NostoProviderProps) {
const {
account,
multiCurrency = false,
host,
children,
recommendationComponent,
shopifyMarkets
} = props
const [clientScriptLoadedState, setClientScriptLoadedState] = React.useState(false)
const clientScriptLoaded = React.useMemo(() => clientScriptLoadedState, [clientScriptLoadedState])

// Pass currentVariation as empty string if multiCurrency is disabled
const currentVariation = multiCurrency ? props.currentVariation : ""

// Set responseMode for loading campaigns:
const responseMode = isValidElement(recommendationComponent) ? "JSON_ORIGINAL" : "HTML"

useEffect(() => {
if (!window.nostojs) {
window.nostojs = (cb: (api: NostoClient) => void) => {
(window.nostojs.q = window.nostojs.q || []).push(cb)
}
window.nostojs(api => api.setAutoLoad(false))
}

if (!isNostoLoaded() && !shopifyMarkets) {
const script = document.createElement("script")
script.type = "text/javascript"
script.src = "//" + (host || "connect.nosto.com") + "/include/" + account
script.async = true
script.setAttribute("nosto-client-script", "")

script.onload = () => {
if ("nostoReactTest" in window) {
window.nosto?.reload({
site: "localhost",
})
}
setClientScriptLoadedState(true)
}
document.body.appendChild(script)
}

// Enable Shopify markets functionality:
if (shopifyMarkets) {
const existingScript = document.querySelector("[nosto-client-script]")
const nostoSandbox = document.querySelector("#nosto-sandbox")

if (
!existingScript ||
existingScript?.getAttribute("nosto-language") !== shopifyMarkets?.language ||
existingScript?.getAttribute("nosto-market-id") !== shopifyMarkets?.marketId
) {
if (clientScriptLoadedState) {
setClientScriptLoadedState(false)
}

existingScript?.parentNode?.removeChild(existingScript)
nostoSandbox?.parentNode?.removeChild(nostoSandbox)

const script = document.createElement("script")
script.type = "text/javascript"
script.src =
"//" +
(host || "connect.nosto.com") +
`/script/shopify/market/nosto.js?merchant=${account}&market=${
shopifyMarkets.marketId || ""
}&locale=${shopifyMarkets?.language?.toLowerCase() || ""}`
script.async = true
script.setAttribute("nosto-client-script", "")
script.setAttribute("nosto-language", shopifyMarkets?.language || "")
script.setAttribute("nosto-market-id", String(shopifyMarkets?.marketId))

script.onload = () => {
if ("nostoReactTest" in window) {
window.nosto?.reload({
site: "localhost",
})
}
setClientScriptLoadedState(true)
}
document.body.appendChild(script)
}
}
}, [clientScriptLoadedState, shopifyMarkets])
const { clientScriptLoaded } = useLoadClientScript(props)

return (
<NostoContext.Provider
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { useDeepCompareEffect } from "./useDeepCompareEffect"
export { useNostoApi } from "./useNostoApi"
export { useNostoContext } from "./useNostoContext"
export { useRenderCampaigns } from "./useRenderCampaigns"
export { useRenderCampaigns } from "./useRenderCampaigns"
export { useLoadClientScript } from "./useLoadClientScript"
82 changes: 82 additions & 0 deletions src/hooks/useLoadClientScript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { useState, useMemo, useEffect } from "react"
import { isNostoLoaded } from "../components/helpers"
import type { NostoClient } from "../types"
import type { NostoProviderProps } from "../components/NostoProvider"

type NostoScriptProps = Pick<NostoProviderProps, "account" | "host" | "shopifyMarkets">

export function useLoadClientScript(props: NostoScriptProps) {
const { host, account, shopifyMarkets } = props
const [clientScriptLoadedState, setClientScriptLoadedState] = useState(false)
const clientScriptLoaded = useMemo(() => clientScriptLoadedState, [clientScriptLoadedState])

useEffect(() => {
const scriptOnload = () => {
if ("nostoReactTest" in window) {
window.nosto?.reload({
site: "localhost"
})
}
setClientScriptLoadedState(true)
}

// Create script element
function createScriptElement(urlPartial: string) {
const scriptEl = document.createElement("script")
scriptEl.type = "text/javascript"
scriptEl.src = `//${(host || "connect.nosto.com")}${urlPartial}`
scriptEl.async = true
scriptEl.setAttribute("nosto-client-script", "")
return scriptEl
}

// Load Nosto API stub
if (!window.nostojs) {
window.nostojs = (cb: (api: NostoClient) => void) => {
(window.nostojs.q = window.nostojs.q || []).push(cb)
}
window.nostojs(api => api.setAutoLoad(false))
}

// Load Nosto client script if not already loaded externally
if (!isNostoLoaded() && !shopifyMarkets) {
const urlPartial = `/include/${account}`
const script = createScriptElement(urlPartial)
script.onload = scriptOnload
document.body.appendChild(script)
}

// Load Shopify Markets scripts
if (shopifyMarkets) {
const existingScript = document.querySelector("[nosto-client-script]")
const marketId = String(shopifyMarkets?.marketId || "")
const language = shopifyMarkets?.language || ""

const existingScriptAttributes =
existingScript?.getAttribute("nosto-language") !== language ||
existingScript?.getAttribute("nosto-market-id") !== marketId

if (!existingScript || existingScriptAttributes) {
if (clientScriptLoadedState) {
setClientScriptLoadedState(false)
}

const nostoSandbox = document.querySelector("#nosto-sandbox")

existingScript?.parentNode?.removeChild(existingScript)
nostoSandbox?.parentNode?.removeChild(nostoSandbox)

const urlPartial =
`/script/shopify/market/nosto.js?merchant=${account}&market=${marketId}&locale=${language.toLowerCase()}`
const script = createScriptElement(urlPartial)
script.setAttribute("nosto-language", language)
script.setAttribute("nosto-market-id", marketId)
script.onload = scriptOnload
document.body.appendChild(script)
}
}

}, [clientScriptLoadedState, shopifyMarkets])

return { clientScriptLoaded }
}

0 comments on commit 6401719

Please sign in to comment.