@nosto/nosto-react 2.2.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/index.d.ts +13 -16
  2. package/dist/index.es.js +257 -866
  3. package/dist/index.umd.js +1 -25
  4. package/package.json +3 -3
  5. package/src/components/Nosto404.tsx +2 -25
  6. package/src/components/NostoCategory.tsx +2 -30
  7. package/src/components/NostoCheckout.tsx +2 -25
  8. package/src/components/NostoHome.tsx +2 -26
  9. package/src/components/NostoOrder.tsx +2 -33
  10. package/src/components/NostoOther.tsx +2 -25
  11. package/src/components/NostoPlacement.tsx +1 -1
  12. package/src/components/NostoProduct.tsx +2 -32
  13. package/src/components/NostoProvider.tsx +11 -10
  14. package/src/components/NostoSearch.tsx +2 -30
  15. package/src/components/NostoSession.tsx +2 -43
  16. package/src/components/helpers.ts +2 -2
  17. package/src/context.ts +0 -1
  18. package/src/hooks/scriptLoader.ts +4 -4
  19. package/src/hooks/useDeepCompareEffect.ts +4 -7
  20. package/src/hooks/useLoadClientScript.ts +9 -4
  21. package/src/hooks/useNosto404.tsx +25 -0
  22. package/src/hooks/useNostoApi.ts +4 -11
  23. package/src/hooks/useNostoCategory.tsx +31 -0
  24. package/src/hooks/useNostoCheckout.tsx +25 -0
  25. package/src/hooks/useNostoContext.ts +2 -3
  26. package/src/hooks/useNostoHome.tsx +25 -0
  27. package/src/hooks/useNostoOrder.tsx +35 -0
  28. package/src/hooks/useNostoOther.tsx +25 -0
  29. package/src/hooks/useNostoProduct.tsx +37 -0
  30. package/src/hooks/useNostoSearch.tsx +31 -0
  31. package/src/hooks/useNostoSession.tsx +33 -0
  32. package/src/hooks/useRenderCampaigns.tsx +10 -8
  33. package/src/index.ts +21 -2
  34. package/src/types.ts +775 -733
  35. package/src/utils/types.ts +5 -3
  36. package/src/components/index.ts +0 -11
  37. package/src/hooks/index.ts +0 -5
@@ -0,0 +1,25 @@
1
+ import { useNostoApi } from "./useNostoApi"
2
+ import { useRenderCampaigns } from "./useRenderCampaigns"
3
+
4
+ /**
5
+ * @group Hooks
6
+ */
7
+ export type Nosto404Props = { placements?: string[] }
8
+
9
+ /**
10
+ * You can personalise your cart and checkout pages by using the `useNosto404` hook.
11
+ *
12
+ * @group Hooks
13
+ */
14
+ export function useNosto404(props?: Nosto404Props) {
15
+ const { renderCampaigns } = useRenderCampaigns()
16
+
17
+ useNostoApi(async api => {
18
+ const data = await api
19
+ .defaultSession()
20
+ .viewNotFound()
21
+ .setPlacements(props?.placements || api.placements.getPlacements())
22
+ .load()
23
+ renderCampaigns(data)
24
+ })
25
+ }
@@ -3,20 +3,13 @@ import { useNostoContext } from "./useNostoContext"
3
3
  import { NostoClient } from "../types"
4
4
  import { useDeepCompareEffect } from "./useDeepCompareEffect"
5
5
 
6
- export function useNostoApi(
7
- cb: (api: NostoClient) => void,
8
- deps?: DependencyList,
9
- flags?: { deep?: boolean }
10
- ): void {
11
- const { clientScriptLoaded, currentVariation, responseMode } = useNostoContext()
6
+ export function useNostoApi(cb: (api: NostoClient) => void, deps?: DependencyList, flags?: { deep?: boolean }): void {
7
+ const { clientScriptLoaded } = useNostoContext()
12
8
  const useEffectFn = flags?.deep ? useDeepCompareEffect : useEffect
13
9
 
14
10
  useEffectFn(() => {
15
11
  if (clientScriptLoaded) {
16
- window.nostojs(api => {
17
- api.defaultSession().setVariation(currentVariation!).setResponseMode(responseMode)
18
- cb(api)
19
- })
12
+ window.nostojs(cb)
20
13
  }
21
- }, [clientScriptLoaded, currentVariation, responseMode, ...(deps ?? [])])
14
+ }, [clientScriptLoaded, ...(deps ?? [])])
22
15
  }
@@ -0,0 +1,31 @@
1
+ import { useNostoApi } from "./useNostoApi"
2
+ import { useRenderCampaigns } from "./useRenderCampaigns"
3
+
4
+ /**
5
+ * @group Hooks
6
+ */
7
+ export type NostoCategoryProps = {
8
+ category: string
9
+ placements?: string[]
10
+ }
11
+
12
+ /**
13
+ * You can personalise your category and collection pages by using the useNostoCategory hook.
14
+ *
15
+ * @group Hooks
16
+ */
17
+ export function useNostoCategory({ category, placements }: NostoCategoryProps) {
18
+ const { renderCampaigns } = useRenderCampaigns()
19
+
20
+ useNostoApi(
21
+ async api => {
22
+ const data = await api
23
+ .defaultSession()
24
+ .viewCategory(category)
25
+ .setPlacements(placements || api.placements.getPlacements())
26
+ .load()
27
+ renderCampaigns(data)
28
+ },
29
+ [category]
30
+ )
31
+ }
@@ -0,0 +1,25 @@
1
+ import { useNostoApi } from "./useNostoApi"
2
+ import { useRenderCampaigns } from "./useRenderCampaigns"
3
+
4
+ /**
5
+ * @group Hooks
6
+ */
7
+ export type NostoCheckoutProps = { placements?: string[] }
8
+
9
+ /**
10
+ * You can personalise your cart and checkout pages by using the useNostoCheckout hook.
11
+ *
12
+ * @group Hooks
13
+ */
14
+ export function useNostoCheckout(props?: NostoCheckoutProps) {
15
+ const { renderCampaigns } = useRenderCampaigns()
16
+
17
+ useNostoApi(async api => {
18
+ const data = await api
19
+ .defaultSession()
20
+ .viewCart()
21
+ .setPlacements(props?.placements || api.placements.getPlacements())
22
+ .load()
23
+ renderCampaigns(data)
24
+ })
25
+ }
@@ -7,6 +7,5 @@ import { NostoContext, NostoContextType } from "../context"
7
7
  * @group Essential Functions
8
8
  */
9
9
  export function useNostoContext(): NostoContextType {
10
- return useContext(NostoContext)
11
- }
12
-
10
+ return useContext(NostoContext)
11
+ }
@@ -0,0 +1,25 @@
1
+ import { useNostoApi } from "./useNostoApi"
2
+ import { useRenderCampaigns } from "./useRenderCampaigns"
3
+
4
+ /**
5
+ * @group Hooks
6
+ */
7
+ export type NostoHomeProps = { placements?: string[] }
8
+
9
+ /**
10
+ * You can personalise your home page by using the useNostoHome hook.
11
+ *
12
+ * @group Hooks
13
+ */
14
+ export function useNostoHome(props?: NostoHomeProps) {
15
+ const { renderCampaigns } = useRenderCampaigns()
16
+
17
+ useNostoApi(async api => {
18
+ const data = await api
19
+ .defaultSession()
20
+ .viewFrontPage()
21
+ .setPlacements(props?.placements || api.placements.getPlacements())
22
+ .load()
23
+ renderCampaigns(data)
24
+ })
25
+ }
@@ -0,0 +1,35 @@
1
+ import { snakeize } from "../utils/snakeize"
2
+ import { Order } from "../types"
3
+ import { useRenderCampaigns } from "./useRenderCampaigns"
4
+ import { useNostoApi } from "./useNostoApi"
5
+ import { ToCamelCase } from "../utils/types"
6
+
7
+ /**
8
+ * @group Hooks
9
+ */
10
+ export type NostoOrderProps = {
11
+ order: Order | ToCamelCase<Order>
12
+ placements?: string[]
13
+ }
14
+
15
+ /**
16
+ * You can personalise your order-confirmation/thank-you page by using the `useNostoOrder` hook.
17
+ *
18
+ * @group Hooks
19
+ */
20
+ export function useNostoOrder({ order, placements }: NostoOrderProps) {
21
+ const { renderCampaigns } = useRenderCampaigns()
22
+
23
+ useNostoApi(
24
+ async api => {
25
+ const data = await api
26
+ .defaultSession()
27
+ .addOrder(snakeize(order))
28
+ .setPlacements(placements || api.placements.getPlacements())
29
+ .load()
30
+ renderCampaigns(data)
31
+ },
32
+ [order],
33
+ { deep: true }
34
+ )
35
+ }
@@ -0,0 +1,25 @@
1
+ import { useNostoApi } from "./useNostoApi"
2
+ import { useRenderCampaigns } from "./useRenderCampaigns"
3
+
4
+ /**
5
+ * @group Hooks
6
+ */
7
+ export type NostoOtherProps = { placements?: string[] }
8
+
9
+ /**
10
+ * You can personalise your miscellaneous pages by using the useNostoOther hook.
11
+ *
12
+ * @group Hooks
13
+ */
14
+ export function useNostoOther(props?: NostoOtherProps) {
15
+ const { renderCampaigns } = useRenderCampaigns()
16
+
17
+ useNostoApi(async api => {
18
+ const data = await api
19
+ .defaultSession()
20
+ .viewOther()
21
+ .setPlacements(props?.placements || api.placements.getPlacements())
22
+ .load()
23
+ renderCampaigns(data)
24
+ })
25
+ }
@@ -0,0 +1,37 @@
1
+ import { Product } from "../types"
2
+ import { useNostoApi } from "./useNostoApi"
3
+ import { useRenderCampaigns } from "./useRenderCampaigns"
4
+
5
+ /**
6
+ * @group Hooks
7
+ */
8
+ export type NostoProductProps = {
9
+ product: string
10
+ tagging?: Product
11
+ placements?: string[]
12
+ }
13
+
14
+ /**
15
+ * You can personalise your product pages by using the useNostoProduct hook.
16
+ *
17
+ * @group Hooks
18
+ */
19
+ export function useNostoProduct({ product, tagging, placements }: NostoProductProps) {
20
+ const { renderCampaigns } = useRenderCampaigns()
21
+
22
+ if (tagging && !tagging.product_id) {
23
+ throw new Error("The product object must contain a product_id property")
24
+ }
25
+
26
+ useNostoApi(
27
+ async api => {
28
+ const data = await api
29
+ .defaultSession()
30
+ .viewProduct(tagging ?? product)
31
+ .setPlacements(placements || api.placements.getPlacements())
32
+ .load()
33
+ renderCampaigns(data)
34
+ },
35
+ [product, tagging?.selected_sku_id]
36
+ )
37
+ }
@@ -0,0 +1,31 @@
1
+ import { useNostoApi } from "./useNostoApi"
2
+ import { useRenderCampaigns } from "./useRenderCampaigns"
3
+
4
+ /**
5
+ * @group Components
6
+ */
7
+ export type NostoSearchProps = {
8
+ query: string
9
+ placements?: string[]
10
+ }
11
+
12
+ /**
13
+ * You can personalise your search pages by using the useNostoSearch hook.
14
+ *
15
+ * @group Hooks
16
+ */
17
+ export function useNostoSearch({ query, placements }: NostoSearchProps) {
18
+ const { renderCampaigns } = useRenderCampaigns()
19
+
20
+ useNostoApi(
21
+ async api => {
22
+ const data = await api
23
+ .defaultSession()
24
+ .viewSearch(query)
25
+ .setPlacements(placements || api.placements.getPlacements())
26
+ .load()
27
+ renderCampaigns(data)
28
+ },
29
+ [query]
30
+ )
31
+ }
@@ -0,0 +1,33 @@
1
+ import { snakeize } from "../utils/snakeize"
2
+ import { Cart as CartSnakeCase, Customer as CustomerSnakeCase } from "../types"
3
+ import { ToCamelCase } from "../utils/types"
4
+ import { useNostoContext } from "./useNostoContext"
5
+ import { useDeepCompareEffect } from "./useDeepCompareEffect"
6
+
7
+ /**
8
+ * @group Hooks
9
+ */
10
+ export type NostoSessionProps = {
11
+ cart?: CartSnakeCase | ToCamelCase<CartSnakeCase>
12
+ customer?: CustomerSnakeCase | ToCamelCase<CustomerSnakeCase>
13
+ }
14
+
15
+ /**
16
+ * Nosto React requires that you pass it the details of current cart contents and the details of the currently logged-in customer, if any, on every route change.
17
+ *
18
+ * @group Hooks
19
+ */
20
+ export function useNostoSession({ cart, customer }: NostoSessionProps = {}) {
21
+ const { clientScriptLoaded } = useNostoContext()
22
+
23
+ useDeepCompareEffect(() => {
24
+ const currentCart = cart ? snakeize(cart) : undefined
25
+ const currentCustomer = customer ? snakeize(customer) : undefined
26
+
27
+ if (clientScriptLoaded) {
28
+ window.nostojs(api => {
29
+ api.defaultSession().setCart(currentCart).setCustomer(currentCustomer).viewOther().load({ skipPageViews: true })
30
+ })
31
+ }
32
+ }, [clientScriptLoaded, cart, customer])
33
+ }
@@ -4,18 +4,20 @@ import { ActionResponse, Recommendation } from "../types"
4
4
  import { useNostoContext } from "./useNostoContext"
5
5
  import { RecommendationComponent } from "../context"
6
6
 
7
- // RecommendationComponent for client-side rendering:
8
- function RecommendationComponentWrapper(props: {
9
- recommendationComponent: RecommendationComponent,
10
- nostoRecommendation: Recommendation }) {
7
+ type CampaignData = Pick<ActionResponse, "campaigns" | "recommendations">
11
8
 
9
+ // RecommendationComponent for client-side rendering:
10
+ function RecommendationComponentWrapper(props: {
11
+ recommendationComponent: RecommendationComponent
12
+ nostoRecommendation: Recommendation
13
+ }) {
12
14
  return cloneElement(props.recommendationComponent, {
13
15
  // eslint-disable-next-line react/prop-types
14
- nostoRecommendation: props.nostoRecommendation,
16
+ nostoRecommendation: props.nostoRecommendation
15
17
  })
16
18
  }
17
19
 
18
- function injectCampaigns(data: ActionResponse) {
20
+ function injectCampaigns(data: CampaignData) {
19
21
  if (!window.nostojs) {
20
22
  throw new Error("Nosto has not yet been initialized")
21
23
  }
@@ -32,7 +34,7 @@ export function useRenderCampaigns() {
32
34
  return { renderCampaigns: injectCampaigns }
33
35
  }
34
36
 
35
- function renderCampaigns(data: ActionResponse) {
37
+ function renderCampaigns(data: CampaignData) {
36
38
  // render recommendation component into placements:
37
39
  const recommendations = data.campaigns?.recommendations ?? {}
38
40
  for (const key in recommendations) {
@@ -56,4 +58,4 @@ export function useRenderCampaigns() {
56
58
  }
57
59
 
58
60
  return { renderCampaigns }
59
- }
61
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,24 @@
1
1
  export type { Cart, Customer, Product, Order, Recommendation } from "./types"
2
- export * from "./components"
3
2
  export { type ScriptLoadOptions } from "./hooks/scriptLoader"
4
3
  export { NostoContext, type NostoContextType } from "./context"
5
- export { useNostoContext } from "./hooks/useNostoContext"
4
+ export { useNostoContext } from "./hooks/useNostoContext"
5
+ export * from "./components/Nosto404"
6
+ export * from "./components/NostoCategory"
7
+ export * from "./components/NostoCheckout"
8
+ export * from "./components/NostoHome"
9
+ export * from "./components/NostoOrder"
10
+ export * from "./components/NostoOther"
11
+ export * from "./components/NostoPlacement"
12
+ export * from "./components/NostoProduct"
13
+ export * from "./components/NostoProvider"
14
+ export * from "./components/NostoSearch"
15
+ export * from "./components/NostoSession"
16
+ export * from "./hooks/useNosto404"
17
+ export * from "./hooks/useNostoCategory"
18
+ export * from "./hooks/useNostoCheckout"
19
+ export * from "./hooks/useNostoHome"
20
+ export * from "./hooks/useNostoOrder"
21
+ export * from "./hooks/useNostoOther"
22
+ export * from "./hooks/useNostoProduct"
23
+ export * from "./hooks/useNostoSearch"
24
+ export * from "./hooks/useNostoSession"