@nosto/nosto-react 2.2.1 → 2.3.0

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 (38) hide show
  1. package/LICENSE +1 -1
  2. package/dist/index.d.ts +23 -192
  3. package/dist/index.es.js +249 -221
  4. package/dist/index.umd.js +1 -1
  5. package/package.json +20 -17
  6. package/src/components/Nosto404.tsx +2 -25
  7. package/src/components/NostoCategory.tsx +2 -30
  8. package/src/components/NostoCheckout.tsx +2 -25
  9. package/src/components/NostoHome.tsx +2 -26
  10. package/src/components/NostoOrder.tsx +2 -33
  11. package/src/components/NostoOther.tsx +2 -25
  12. package/src/components/NostoPlacement.tsx +1 -1
  13. package/src/components/NostoProduct.tsx +2 -32
  14. package/src/components/NostoProvider.tsx +5 -9
  15. package/src/components/NostoSearch.tsx +2 -30
  16. package/src/components/NostoSession.tsx +2 -42
  17. package/src/context.ts +2 -2
  18. package/src/hooks/scriptLoader.ts +4 -4
  19. package/src/hooks/useDeepCompareEffect.ts +1 -4
  20. package/src/hooks/useLoadClientScript.ts +26 -17
  21. package/src/hooks/useNosto404.tsx +25 -0
  22. package/src/hooks/useNostoApi.ts +4 -7
  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 +43 -0
  30. package/src/hooks/useNostoSearch.tsx +31 -0
  31. package/src/hooks/useNostoSession.tsx +34 -0
  32. package/src/hooks/useRenderCampaigns.tsx +12 -9
  33. package/src/index.ts +23 -3
  34. package/src/types.ts +1 -923
  35. package/src/utils/types.ts +5 -3
  36. package/src/components/helpers.ts +0 -3
  37. package/src/components/index.ts +0 -11
  38. package/src/hooks/index.ts +0 -5
@@ -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 { useRenderCampaigns } from "./useRenderCampaigns"
3
+ import { useNostoApi } from "./useNostoApi"
4
+ import { ToCamelCase } from "../utils/types"
5
+ import { WebsiteOrder as Order } from "@nosto/nosto-js/client"
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,43 @@
1
+ import { useNostoApi } from "./useNostoApi"
2
+ import { useRenderCampaigns } from "./useRenderCampaigns"
3
+ import { Product } from "@nosto/nosto-js/client"
4
+
5
+ /**
6
+ * @group Hooks
7
+ */
8
+ export type NostoProductProps = {
9
+ product: string
10
+ reference?: string
11
+ tagging?: Product
12
+ placements?: string[]
13
+ }
14
+
15
+ /**
16
+ * You can personalise your product pages by using the useNostoProduct hook.
17
+ *
18
+ * @group Hooks
19
+ */
20
+ export function useNostoProduct({ product, tagging, placements, reference }: NostoProductProps) {
21
+ const { renderCampaigns } = useRenderCampaigns()
22
+
23
+ if (tagging && !tagging.product_id) {
24
+ throw new Error("The product object must contain a product_id property")
25
+ }
26
+
27
+ const productId = tagging?.product_id ?? product
28
+
29
+ useNostoApi(
30
+ async api => {
31
+ const action = api
32
+ .defaultSession()
33
+ .viewProduct(tagging ?? product)
34
+ .setPlacements(placements || api.placements.getPlacements())
35
+ if (reference) {
36
+ action.setRef(productId, reference)
37
+ }
38
+ const data = await action.load()
39
+ renderCampaigns(data)
40
+ },
41
+ [productId, tagging?.selected_sku_id]
42
+ )
43
+ }
@@ -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,34 @@
1
+ import { snakeize } from "../utils/snakeize"
2
+ import { PushedCustomer as CustomerSnakeCase, Cart as CartSnakeCase } from "@nosto/nosto-js/client"
3
+ import { ToCamelCase } from "../utils/types"
4
+ import { useNostoContext } from "./useNostoContext"
5
+ import { useDeepCompareEffect } from "./useDeepCompareEffect"
6
+ import { nostojs } from "@nosto/nosto-js"
7
+
8
+ /**
9
+ * @group Hooks
10
+ */
11
+ export type NostoSessionProps = {
12
+ cart?: CartSnakeCase | ToCamelCase<CartSnakeCase>
13
+ customer?: CustomerSnakeCase | ToCamelCase<CustomerSnakeCase>
14
+ }
15
+
16
+ /**
17
+ * 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.
18
+ *
19
+ * @group Hooks
20
+ */
21
+ export function useNostoSession({ cart, customer }: NostoSessionProps = {}) {
22
+ const { clientScriptLoaded } = useNostoContext()
23
+
24
+ useDeepCompareEffect(() => {
25
+ const currentCart = cart ? snakeize(cart) : undefined
26
+ const currentCustomer = customer ? snakeize(customer) : undefined
27
+
28
+ if (clientScriptLoaded) {
29
+ nostojs(api => {
30
+ api.defaultSession().setCart(currentCart).setCustomer(currentCustomer).viewOther().load({ skipPageViews: true })
31
+ })
32
+ }
33
+ }, [clientScriptLoaded, cart, customer])
34
+ }
@@ -1,28 +1,31 @@
1
1
  import { cloneElement, useRef } from "react"
2
2
  import { createRoot, Root } from "react-dom/client"
3
- import { ActionResponse, Recommendation } from "../types"
3
+ import { Recommendation } from "../types"
4
4
  import { useNostoContext } from "./useNostoContext"
5
5
  import { RecommendationComponent } from "../context"
6
+ import { ActionResponse, API } from "@nosto/nosto-js/client"
7
+ import { nostojs } from "@nosto/nosto-js"
6
8
 
7
9
  type CampaignData = Pick<ActionResponse, "campaigns" | "recommendations">
8
10
 
9
11
  // RecommendationComponent for client-side rendering:
10
- function RecommendationComponentWrapper(props: {
11
- recommendationComponent: RecommendationComponent,
12
- nostoRecommendation: Recommendation }) {
13
-
12
+ function RecommendationComponentWrapper(props: {
13
+ recommendationComponent: RecommendationComponent
14
+ nostoRecommendation: Recommendation
15
+ }) {
14
16
  return cloneElement(props.recommendationComponent, {
15
17
  // eslint-disable-next-line react/prop-types
16
- nostoRecommendation: props.nostoRecommendation,
18
+ nostoRecommendation: props.nostoRecommendation
17
19
  })
18
20
  }
19
21
 
20
22
  function injectCampaigns(data: CampaignData) {
23
+ // @ts-expect-error not defined
21
24
  if (!window.nostojs) {
22
25
  throw new Error("Nosto has not yet been initialized")
23
26
  }
24
- window.nostojs(api => {
25
- api.placements.injectCampaigns(data.recommendations)
27
+ nostojs(api => {
28
+ api.placements.injectCampaigns(data.recommendations as Parameters<API['placements']['injectCampaigns']>[0])
26
29
  })
27
30
  }
28
31
 
@@ -58,4 +61,4 @@ export function useRenderCampaigns() {
58
61
  }
59
62
 
60
63
  return { renderCampaigns }
61
- }
64
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,25 @@
1
- export type { Cart, Customer, Product, Order, Recommendation } from "./types"
2
- export * from "./components"
1
+ export type { Product, PushedCustomer as Customer, Cart, WebsiteOrder as Order } from "@nosto/nosto-js/client"
2
+ export type { Recommendation } from "./types"
3
3
  export { type ScriptLoadOptions } from "./hooks/scriptLoader"
4
4
  export { NostoContext, type NostoContextType } from "./context"
5
- export { useNostoContext } from "./hooks/useNostoContext"
5
+ export { useNostoContext } from "./hooks/useNostoContext"
6
+ export * from "./components/Nosto404"
7
+ export * from "./components/NostoCategory"
8
+ export * from "./components/NostoCheckout"
9
+ export * from "./components/NostoHome"
10
+ export * from "./components/NostoOrder"
11
+ export * from "./components/NostoOther"
12
+ export * from "./components/NostoPlacement"
13
+ export * from "./components/NostoProduct"
14
+ export * from "./components/NostoProvider"
15
+ export * from "./components/NostoSearch"
16
+ export * from "./components/NostoSession"
17
+ export * from "./hooks/useNosto404"
18
+ export * from "./hooks/useNostoCategory"
19
+ export * from "./hooks/useNostoCheckout"
20
+ export * from "./hooks/useNostoHome"
21
+ export * from "./hooks/useNostoOrder"
22
+ export * from "./hooks/useNostoOther"
23
+ export * from "./hooks/useNostoProduct"
24
+ export * from "./hooks/useNostoSearch"
25
+ export * from "./hooks/useNostoSession"