From d9151c995fee898974e6402feb3695685a73cbb9 Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Thu, 31 Oct 2024 10:47:15 -0400
Subject: [PATCH 01/15] chore(headless SSR) add missing exports
https://coveord.atlassian.net/browse/KIT-3694
---
packages/headless/src/app/commerce-ssr-engine/types/common.ts | 2 ++
.../headless/src/app/commerce-ssr-engine/types/core-engine.ts | 1 +
packages/headless/src/ssr-commerce.index.ts | 4 ++++
3 files changed, 7 insertions(+)
diff --git a/packages/headless/src/app/commerce-ssr-engine/types/common.ts b/packages/headless/src/app/commerce-ssr-engine/types/common.ts
index e19b4c9bde8..fdf21309c0e 100644
--- a/packages/headless/src/app/commerce-ssr-engine/types/common.ts
+++ b/packages/headless/src/app/commerce-ssr-engine/types/common.ts
@@ -6,11 +6,13 @@ import type {
HasKey,
InferControllerStaticStateMapFromControllers,
InferControllerStaticStateFromController,
+ InferControllerPropsMapFromDefinitions,
} from '../../ssr-engine/types/common.js';
export type {
InferControllerStaticStateFromController,
InferControllerStaticStateMapFromControllers,
+ InferControllerPropsMapFromDefinitions,
};
export enum SolutionType {
diff --git a/packages/headless/src/app/commerce-ssr-engine/types/core-engine.ts b/packages/headless/src/app/commerce-ssr-engine/types/core-engine.ts
index 5c7dc8e06ec..a9d39706164 100644
--- a/packages/headless/src/app/commerce-ssr-engine/types/core-engine.ts
+++ b/packages/headless/src/app/commerce-ssr-engine/types/core-engine.ts
@@ -14,6 +14,7 @@ import {
InferControllerStaticStateMapFromDefinitionsWithSolutionType,
} from './common.js';
+export type {HydrateStaticState, FetchStaticState};
export type EngineDefinitionOptions<
TOptions extends {configuration: EngineConfiguration},
TControllers extends ControllerDefinitionsMap<
diff --git a/packages/headless/src/ssr-commerce.index.ts b/packages/headless/src/ssr-commerce.index.ts
index dc14398af49..2ff89354831 100644
--- a/packages/headless/src/ssr-commerce.index.ts
+++ b/packages/headless/src/ssr-commerce.index.ts
@@ -88,6 +88,7 @@ export type {
AnalyticsConfiguration,
AnalyticsRuntimeEnvironment,
} from './app/engine-configuration.js';
+export {SolutionType} from './app/commerce-ssr-engine/types/common.js';
export type {
ControllerDefinitionsMap,
InferControllerFromDefinition,
@@ -95,6 +96,7 @@ export type {
InferControllerStaticStateFromController,
InferControllerStaticStateMapFromControllers,
InferControllerStaticStateMapFromDefinitionsWithSolutionType,
+ InferControllerPropsMapFromDefinitions,
} from './app/commerce-ssr-engine/types/common.js';
export type {Build} from './app/ssr-engine/types/build.js';
export type {
@@ -102,6 +104,8 @@ export type {
InferStaticState,
InferHydratedState,
InferBuildResult,
+ HydrateStaticState,
+ FetchStaticState,
} from './app/commerce-ssr-engine/types/core-engine.js';
export type {LoggerOptions} from './app/logger.js';
export type {NavigatorContext} from './app/navigatorContextProvider.js';
From 1192473ebc39f82bf7c164ed39bd94d83c77ae19 Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Thu, 31 Oct 2024 10:52:10 -0400
Subject: [PATCH 02/15] add ssr-commerce folder
https://coveord.atlassian.net/browse/KIT-3695
---
packages/headless-react/package.json | 3 +-
.../src/ssr-commerce/client-utils.ts | 65 +++++++
.../src/ssr-commerce/commerce-engine.tsx | 102 +++++++++++
.../src/ssr-commerce/common.tsx | 172 ++++++++++++++++++
.../headless-react/src/ssr-commerce/index.ts | 4 +
.../headless-react/src/ssr-commerce/types.ts | 79 ++++++++
6 files changed, 424 insertions(+), 1 deletion(-)
create mode 100644 packages/headless-react/src/ssr-commerce/client-utils.ts
create mode 100644 packages/headless-react/src/ssr-commerce/commerce-engine.tsx
create mode 100644 packages/headless-react/src/ssr-commerce/common.tsx
create mode 100644 packages/headless-react/src/ssr-commerce/index.ts
create mode 100644 packages/headless-react/src/ssr-commerce/types.ts
diff --git a/packages/headless-react/package.json b/packages/headless-react/package.json
index 5c89bab71f1..f53b3f11e71 100644
--- a/packages/headless-react/package.json
+++ b/packages/headless-react/package.json
@@ -17,7 +17,8 @@
"license": "Apache-2.0",
"type": "module",
"exports": {
- "./ssr": "./dist/ssr/index.js"
+ "./ssr": "./dist/ssr/index.js",
+ "./ssr-commerce": "./dist/ssr-commerce/index.js"
},
"files": [
"dist"
diff --git a/packages/headless-react/src/ssr-commerce/client-utils.ts b/packages/headless-react/src/ssr-commerce/client-utils.ts
new file mode 100644
index 00000000000..c35d1f23732
--- /dev/null
+++ b/packages/headless-react/src/ssr-commerce/client-utils.ts
@@ -0,0 +1,65 @@
+'use client';
+
+import {DependencyList, useEffect, useReducer, useRef} from 'react';
+
+/**
+ * Subscriber is a function that takes a single argument, which is another function `listener` that returns `void`. The Subscriber function itself returns another function that can be used to unsubscribe the `listener`.
+ */
+export type Subscriber = (listener: () => void) => () => void;
+
+export type SnapshotGetter = () => T;
+
+/**
+ * Determine if the given list of dependencies has changed.
+ */
+function useHasDepsChanged(deps: DependencyList) {
+ const ref = useRef(null);
+ if (ref.current === null) {
+ ref.current = deps;
+ return false;
+ }
+ if (
+ ref.current.length === deps.length &&
+ !deps.some((dep, i) => !Object.is(ref.current![i], dep))
+ ) {
+ return false;
+ }
+ ref.current = deps;
+ return true;
+}
+
+/**
+ * Alternate for `useSyncExternalStore` which runs into infinite loops when hooks are used in `getSnapshot`
+ * https://github.com/facebook/react/issues/24529
+ */
+export function useSyncMemoizedStore(
+ subscribe: Subscriber,
+ getSnapshot: SnapshotGetter
+): T {
+ const snapshot = useRef(null);
+ const [, forceRender] = useReducer((s) => s + 1, 0);
+
+ useEffect(() => {
+ let isMounted = true;
+ const unsubscribe = subscribe(() => {
+ if (isMounted) {
+ snapshot.current = getSnapshot();
+ forceRender();
+ }
+ });
+ return () => {
+ isMounted = false;
+ unsubscribe();
+ };
+ }, [subscribe, getSnapshot]);
+
+ // Since useRef does not take a dependencies array changes to dependencies need to be processed explicitly
+ if (
+ useHasDepsChanged([subscribe, getSnapshot]) ||
+ snapshot.current === null
+ ) {
+ snapshot.current = getSnapshot();
+ }
+
+ return snapshot.current;
+}
diff --git a/packages/headless-react/src/ssr-commerce/commerce-engine.tsx b/packages/headless-react/src/ssr-commerce/commerce-engine.tsx
new file mode 100644
index 00000000000..76a0f755837
--- /dev/null
+++ b/packages/headless-react/src/ssr-commerce/commerce-engine.tsx
@@ -0,0 +1,102 @@
+import {
+ Controller,
+ CommerceEngine,
+ ControllerDefinitionsMap,
+ CommerceEngineDefinitionOptions,
+ defineCommerceEngine as defineBaseCommerceEngine,
+ CommerceEngineOptions,
+ SolutionType,
+} from '@coveo/headless/ssr-commerce';
+// Workaround to prevent Next.js erroring about importing CSR only hooks
+import React from 'react';
+import {singleton, SingletonGetter} from '../utils.js';
+import {
+ buildControllerHooks,
+ buildEngineHook,
+ buildHydratedStateProvider,
+ buildStaticStateProvider,
+} from './common.js';
+import {ContextState, ReactEngineDefinition} from './types.js';
+
+export type ReactCommerceEngineDefinition<
+ TControllers extends ControllerDefinitionsMap,
+ TSolutionType extends SolutionType,
+> = ReactEngineDefinition<
+ CommerceEngine,
+ TControllers,
+ CommerceEngineOptions,
+ TSolutionType
+>;
+
+// Wrapper to workaround the limitation that `createContext()` cannot be called directly during SSR in next.js
+export function createSingletonContext<
+ TControllers extends ControllerDefinitionsMap,
+ TSolutionType extends SolutionType = SolutionType,
+>() {
+ return singleton(() =>
+ React.createContext | null>(null)
+ );
+}
+
+/**
+ * Returns controller hooks as well as SSR and CSR context providers that can be used to interact with a Commerce engine
+ * on the server and client side respectively.
+ */
+export function defineCommerceEngine<
+ TControllers extends ControllerDefinitionsMap,
+>(options: CommerceEngineDefinitionOptions) {
+ const singletonContext = createSingletonContext();
+
+ type ContextStateType = SingletonGetter<
+ React.Context | null>
+ >;
+ type ListingContext = ContextStateType;
+ type SearchContext = ContextStateType;
+ type StandaloneContext = ContextStateType;
+
+ const {
+ listingEngineDefinition,
+ searchEngineDefinition,
+ standaloneEngineDefinition,
+ } = defineBaseCommerceEngine({...options});
+ return {
+ useEngine: buildEngineHook(singletonContext),
+ controllers: buildControllerHooks(singletonContext, options.controllers),
+ listingEngineDefinition: {
+ ...listingEngineDefinition,
+ StaticStateProvider: buildStaticStateProvider(
+ singletonContext as ListingContext
+ ),
+
+ HydratedStateProvider: buildHydratedStateProvider(
+ singletonContext as ListingContext
+ ),
+ },
+ searchEngineDefinition: {
+ ...searchEngineDefinition,
+ StaticStateProvider: buildStaticStateProvider(
+ singletonContext as SearchContext
+ ),
+ HydratedStateProvider: buildHydratedStateProvider(
+ singletonContext as SearchContext
+ ),
+ },
+ standaloneEngineDefinition: {
+ ...standaloneEngineDefinition,
+ StaticStateProvider: buildStaticStateProvider(
+ singletonContext as StandaloneContext
+ ),
+ HydratedStateProvider: buildHydratedStateProvider(
+ singletonContext as StandaloneContext
+ ),
+ },
+ };
+}
diff --git a/packages/headless-react/src/ssr-commerce/common.tsx b/packages/headless-react/src/ssr-commerce/common.tsx
new file mode 100644
index 00000000000..ca659653aba
--- /dev/null
+++ b/packages/headless-react/src/ssr-commerce/common.tsx
@@ -0,0 +1,172 @@
+import {
+ Controller,
+ ControllerDefinitionsMap,
+ CoreEngineNext,
+ InferControllerFromDefinition,
+ InferControllerStaticStateMapFromDefinitionsWithSolutionType,
+ InferControllersMapFromDefinition,
+ SolutionType,
+} from '@coveo/headless/ssr-commerce';
+import {
+ useContext,
+ useCallback,
+ useMemo,
+ Context,
+ PropsWithChildren,
+} from 'react';
+import {SingletonGetter, capitalize, mapObject} from '../utils.js';
+import {useSyncMemoizedStore} from './client-utils.js';
+import {
+ ContextHydratedState,
+ ContextState,
+ ControllerHook,
+ InferControllerHooksMapFromDefinition,
+} from './types.js';
+
+export class MissingEngineProviderError extends Error {
+ static message =
+ 'Unable to find Context. Please make sure you are wrapping your component with either `StaticStateProvider` or `HydratedStateProvider` component that can provide the required context.';
+ constructor() {
+ super(MissingEngineProviderError.message);
+ }
+}
+
+function isHydratedStateContext<
+ TEngine extends CoreEngineNext,
+ TControllers extends ControllerDefinitionsMap,
+ TSolutionType extends SolutionType,
+>(
+ ctx: ContextState
+): ctx is ContextHydratedState {
+ return 'engine' in ctx;
+}
+
+function buildControllerHook<
+ TEngine extends CoreEngineNext,
+ TControllers extends ControllerDefinitionsMap,
+ TKey extends keyof TControllers,
+ TSolutionType extends SolutionType,
+>(
+ singletonContext: SingletonGetter<
+ Context | null>
+ >,
+ key: TKey
+): ControllerHook> {
+ return () => {
+ const ctx = useContext(singletonContext.get());
+ if (ctx === null) {
+ throw new MissingEngineProviderError();
+ }
+
+ // Workaround to ensure that 'key' can be used as an index for 'ctx.controllers'. A more robust solution is needed.
+ type ControllerKey = Exclude;
+ const subscribe = useCallback(
+ (listener: () => void) =>
+ isHydratedStateContext(ctx)
+ ? ctx.controllers[key as ControllerKey].subscribe(listener)
+ : () => {},
+ [ctx]
+ );
+ const getStaticState = useCallback(() => ctx.controllers[key].state, [ctx]);
+ const state = useSyncMemoizedStore(subscribe, getStaticState);
+ const controller = useMemo(() => {
+ if (!isHydratedStateContext(ctx)) {
+ return undefined;
+ }
+ const controller = ctx.controllers[key as ControllerKey];
+ const {state: _, subscribe: __, ...remainder} = controller;
+ return mapObject(remainder, (member) =>
+ typeof member === 'function' ? member.bind(controller) : member
+ ) as Omit<
+ InferControllerFromDefinition,
+ 'state' | 'subscribe'
+ >;
+ }, [ctx, key]);
+ return {state, controller};
+ };
+}
+
+export function buildControllerHooks<
+ TEngine extends CoreEngineNext,
+ TControllers extends ControllerDefinitionsMap,
+ TSolutionType extends SolutionType,
+>(
+ singletonContext: SingletonGetter<
+ Context | null>
+ >,
+ controllersMap?: TControllers
+) {
+ return (
+ controllersMap
+ ? Object.fromEntries(
+ Object.keys(controllersMap).map((key) => [
+ `use${capitalize(key)}`,
+ buildControllerHook(singletonContext, key),
+ ])
+ )
+ : {}
+ ) as InferControllerHooksMapFromDefinition;
+}
+
+export function buildEngineHook<
+ TEngine extends CoreEngineNext,
+ TControllers extends ControllerDefinitionsMap,
+ TSolutionType extends SolutionType,
+>(
+ singletonContext: SingletonGetter<
+ Context | null>
+ >
+) {
+ return () => {
+ const ctx = useContext(singletonContext.get());
+ if (ctx === null) {
+ throw new MissingEngineProviderError();
+ }
+ return isHydratedStateContext(ctx) ? ctx.engine : undefined;
+ };
+}
+
+export function buildStaticStateProvider<
+ TEngine extends CoreEngineNext,
+ TControllers extends ControllerDefinitionsMap,
+ TSolutionType extends SolutionType,
+>(
+ singletonContext: SingletonGetter<
+ Context | null>
+ >
+) {
+ return ({
+ controllers,
+ children,
+ }: PropsWithChildren<{
+ controllers: InferControllerStaticStateMapFromDefinitionsWithSolutionType<
+ TControllers,
+ TSolutionType
+ >;
+ }>) => {
+ const {Provider} = singletonContext.get();
+ return {children} ;
+ };
+}
+
+export function buildHydratedStateProvider<
+ TEngine extends CoreEngineNext,
+ TControllers extends ControllerDefinitionsMap,
+ TSolutionType extends SolutionType,
+>(
+ singletonContext: SingletonGetter<
+ Context | null>
+ >
+) {
+ return ({
+ engine,
+ controllers,
+ children,
+ }: PropsWithChildren<{
+ engine: TEngine;
+ controllers: InferControllersMapFromDefinition;
+ }>) => {
+ const {Provider} = singletonContext.get();
+ return {children} ;
+ };
+}
diff --git a/packages/headless-react/src/ssr-commerce/index.ts b/packages/headless-react/src/ssr-commerce/index.ts
new file mode 100644
index 00000000000..2e2a5a56881
--- /dev/null
+++ b/packages/headless-react/src/ssr-commerce/index.ts
@@ -0,0 +1,4 @@
+export {defineCommerceEngine} from './commerce-engine.js';
+export type {ReactCommerceEngineDefinition} from './commerce-engine.js';
+export {MissingEngineProviderError} from './common.js';
+export * from '@coveo/headless/ssr-commerce';
diff --git a/packages/headless-react/src/ssr-commerce/types.ts b/packages/headless-react/src/ssr-commerce/types.ts
new file mode 100644
index 00000000000..9511433e339
--- /dev/null
+++ b/packages/headless-react/src/ssr-commerce/types.ts
@@ -0,0 +1,79 @@
+import {
+ Controller,
+ ControllerDefinitionsMap,
+ InferControllerFromDefinition,
+ InferControllersMapFromDefinition,
+ InferControllerStaticStateMapFromDefinitionsWithSolutionType,
+ EngineDefinition,
+ SolutionType,
+ CoreEngineNext,
+} from '@coveo/headless/ssr-commerce';
+import {FunctionComponent, PropsWithChildren} from 'react';
+
+export type ContextStaticState<
+ TEngine extends CoreEngineNext,
+ TControllers extends ControllerDefinitionsMap,
+ TSolutionType extends SolutionType,
+> = {
+ controllers: InferControllerStaticStateMapFromDefinitionsWithSolutionType<
+ TControllers,
+ TSolutionType
+ >;
+};
+
+export type ContextHydratedState<
+ TEngine extends CoreEngineNext,
+ TControllers extends ControllerDefinitionsMap,
+ TSolutionType extends SolutionType,
+> = {
+ engine: TEngine;
+ controllers: InferControllersMapFromDefinition;
+};
+
+export type ContextState<
+ TEngine extends CoreEngineNext,
+ TControllers extends ControllerDefinitionsMap,
+ TSolutionType extends SolutionType,
+> =
+ | ContextStaticState
+ | ContextHydratedState;
+
+export type ControllerHook = () => {
+ state: TController['state'];
+ controller?: Omit;
+};
+
+export type InferControllerHooksMapFromDefinition<
+ TControllers extends ControllerDefinitionsMap,
+> = {
+ [K in keyof TControllers as `use${Capitalize<
+ K extends string ? K : never
+ >}`]: ControllerHook>;
+};
+
+export type ReactEngineDefinition<
+ TEngine extends CoreEngineNext,
+ TControllers extends ControllerDefinitionsMap,
+ TEngineOptions,
+ TSolutionType extends SolutionType,
+> = EngineDefinition & {
+ controllers: InferControllerHooksMapFromDefinition;
+ useEngine(): TEngine | undefined;
+ StaticStateProvider: FunctionComponent<
+ PropsWithChildren<{
+ controllers: InferControllerStaticStateMapFromDefinitionsWithSolutionType<
+ TControllers,
+ TSolutionType
+ >;
+ }>
+ >;
+ HydratedStateProvider: FunctionComponent<
+ PropsWithChildren<{
+ engine: TEngine;
+ controllers: InferControllersMapFromDefinition<
+ TControllers,
+ TSolutionType
+ >;
+ }>
+ >;
+};
From 34a87679b663a5dddd17e69ceaaa9123b371bc85 Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Thu, 31 Oct 2024 11:05:30 -0400
Subject: [PATCH 03/15] update readme
https://coveord.atlassian.net/browse/KIT-3695
---
packages/headless-react/README.md | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/packages/headless-react/README.md b/packages/headless-react/README.md
index b75d204cf12..16ccd9b3cf2 100644
--- a/packages/headless-react/README.md
+++ b/packages/headless-react/README.md
@@ -1,9 +1,13 @@
# Headless React Utils for SSR
-`@coveo/headless-react/ssr` provides React utilities for server-side rendering with headless controllers.
+`@coveo/headless-react` provides React utilities for server-side rendering with headless controllers. This package includes two sub-packages:
+
+- `@coveo/headless-react/ssr`: For general server-side rendering with headless controllers.
+- `@coveo/headless-react/ssr-commerce`: For implementing a commerce storefront with server-side rendering.
## Learn more
+
+
- Checkout our [Documentation](https://docs.coveo.com/en/headless/latest/usage/headless-server-side-rendering/)
-- Refer to [samples/headless-ssr](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-ssr/) for examples.
-- All exports from `@coveo/headless/ssr` are also available from under `@coveo/headless-react/ssr` as convenience.
+- Refer to [samples/headless-ssr-commerce](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-ssr-commerce/) for examples.
From 727718058c72ffea5e0fd5b2b54d6c46bbe562eb Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Thu, 31 Oct 2024 11:41:50 -0400
Subject: [PATCH 04/15] use react hooks in sample
https://coveord.atlassian.net/browse/KIT-3699
---
package-lock.json | 16 ++-
packages/headless-react/package.json | 10 +-
.../samples/headless-ssr-commerce/README.md | 3 +-
.../app/_components/breadcrumb-manager.tsx | 23 +---
.../app/_components/cart.tsx | 41 ++-----
.../app/_components/facets/category-facet.tsx | 4 +-
.../app/_components/facets/date-facet.tsx | 4 +-
.../_components/facets/facet-generator.tsx | 25 +---
.../app/_components/facets/numeric-facet.tsx | 4 +-
.../app/_components/facets/regular-facet.tsx | 4 +-
.../app/_components/instant-product.tsx | 28 +----
.../app/_components/pages/listing-page.tsx | 116 +++++-------------
.../app/_components/pages/product-page.tsx | 7 +-
.../app/_components/pages/recommendation.tsx | 55 ---------
.../app/_components/pages/search-page.tsx | 116 +++++-------------
.../app/_components/pagination.tsx | 21 +---
.../app/_components/product-list.tsx | 27 +---
.../app/_components/recent-queries.tsx | 27 +---
.../app/_components/recommendation-list.tsx | 30 ++---
.../app/_components/search-box.tsx | 68 +++-------
.../app/_components/show-more.tsx | 33 +----
.../app/_components/sort.tsx | 43 +++----
.../app/_components/standalone-search-box.tsx | 67 +++-------
.../app/_components/summary.tsx | 37 ++----
.../_components/triggers/notify-trigger.tsx | 24 +---
.../_components/triggers/query-trigger.tsx | 23 +---
.../triggers/redirection-trigger.tsx | 24 +---
.../app/_components/triggers/triggers.tsx | 40 +-----
.../app/_lib/commerce-engine-config.ts | 4 +-
.../app/_lib/commerce-engine.ts | 27 +++-
.../app/_lib/navigatorContextProvider.ts | 2 +-
.../headless-ssr-commerce/app/layout.tsx | 3 +-
.../app/listing/page.tsx | 38 +++++-
.../app/recommendation/page.tsx | 29 -----
.../headless-ssr-commerce/app/search/page.tsx | 33 ++++-
.../headless-ssr-commerce/package.json | 4 +-
36 files changed, 317 insertions(+), 743 deletions(-)
delete mode 100644 packages/samples/headless-ssr-commerce/app/_components/pages/recommendation.tsx
delete mode 100644 packages/samples/headless-ssr-commerce/app/recommendation/page.tsx
diff --git a/package-lock.json b/package-lock.json
index ae7dc3bdd6e..133d075bb84 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20900,7 +20900,7 @@
"version": "0.16.8",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==",
- "dev": true
+ "devOptional": true
},
"node_modules/@types/semver": {
"version": "7.5.8",
@@ -57813,8 +57813,6 @@
"@coveo/release": "1.0.0",
"@testing-library/react": "14.3.1",
"@types/jest": "29.5.12",
- "@types/react": "18.3.3",
- "@types/react-dom": "18.3.0",
"@typescript-eslint/eslint-plugin": "7.17.0",
"eslint-plugin-jest-dom": "5.4.0",
"eslint-plugin-react": "7.35.0",
@@ -57829,7 +57827,13 @@
"engines": {
"node": "^20.9.0"
},
+ "optionalDependencies": {
+ "@types/react": "^18.0.0",
+ "@types/react-dom": "^18.0.0"
+ },
"peerDependencies": {
+ "@types/react": "18.3.3",
+ "@types/react-dom": "18.3.0",
"react": "^18",
"react-dom": "^18"
}
@@ -57856,7 +57860,7 @@
"version": "18.2.21",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz",
"integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -57867,7 +57871,7 @@
"version": "18.2.7",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz",
"integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"@types/react": "*"
}
@@ -65142,7 +65146,7 @@
"name": "@coveo/headless-ssr-commerce-samples",
"version": "0.0.0",
"dependencies": {
- "@coveo/headless": "3.5.0",
+ "@coveo/headless-react": "2.0.8",
"next": "14.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
diff --git a/packages/headless-react/package.json b/packages/headless-react/package.json
index f53b3f11e71..e7bbec2da38 100644
--- a/packages/headless-react/package.json
+++ b/packages/headless-react/package.json
@@ -40,8 +40,6 @@
"@coveo/release": "1.0.0",
"@testing-library/react": "14.3.1",
"@types/jest": "29.5.12",
- "@types/react": "18.3.3",
- "@types/react-dom": "18.3.0",
"@typescript-eslint/eslint-plugin": "7.17.0",
"eslint-plugin-jest-dom": "5.4.0",
"eslint-plugin-react": "7.35.0",
@@ -55,7 +53,13 @@
},
"peerDependencies": {
"react": "^18",
- "react-dom": "^18"
+ "react-dom": "^18",
+ "@types/react": "18.3.3",
+ "@types/react-dom": "18.3.0"
+ },
+ "optionalDependencies": {
+ "@types/react": "^18.0.0",
+ "@types/react-dom": "^18.0.0"
},
"engines": {
"node": "^20.9.0"
diff --git a/packages/samples/headless-ssr-commerce/README.md b/packages/samples/headless-ssr-commerce/README.md
index a749fa88c3f..e60a95e80e8 100644
--- a/packages/samples/headless-ssr-commerce/README.md
+++ b/packages/samples/headless-ssr-commerce/README.md
@@ -1,7 +1,6 @@
# Server side rendering examples
-- Demonstrates usage of the framework agnostic `@coveo/headless/ssr-commerce` utils for Server-Side Rendering with headless using Next.js in a commerce app.
-- Although Next.js is used to demonstrate SSR usage for convenience, the utils are not specific to Next.js.
+- Demonstrates usage of the framework `@coveo/headless-react/ssr-commerce` utils for Server-Side Rendering with headless using Next.js in a commerce app.
## Getting Started
diff --git a/packages/samples/headless-ssr-commerce/app/_components/breadcrumb-manager.tsx b/packages/samples/headless-ssr-commerce/app/_components/breadcrumb-manager.tsx
index 0ea61e0d277..01a5f8713c9 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/breadcrumb-manager.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/breadcrumb-manager.tsx
@@ -1,26 +1,15 @@
+'use client';
+
import {
- BreadcrumbManagerState,
NumericFacetValue,
DateFacetValue,
CategoryFacetValue,
- BreadcrumbManager as HeadlessBreadcrumbManager,
RegularFacetValue,
-} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
-
-interface BreadcrumbManagerProps {
- staticState: BreadcrumbManagerState;
- controller?: HeadlessBreadcrumbManager;
-}
-
-export default function BreadcrumbManager(props: BreadcrumbManagerProps) {
- const {staticState, controller} = props;
-
- const [state, setState] = useState(staticState);
+} from '@coveo/headless-react/ssr-commerce';
+import {useBreadcrumbManager} from '../_lib/commerce-engine';
- useEffect(() => {
- controller?.subscribe(() => setState(controller.state));
- }, [controller]);
+export default function BreadcrumbManager() {
+ const {state, controller} = useBreadcrumbManager();
const renderBreadcrumbValue = (
value:
diff --git a/packages/samples/headless-ssr-commerce/app/_components/cart.tsx b/packages/samples/headless-ssr-commerce/app/_components/cart.tsx
index d270c7ad04e..55274cb7b38 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/cart.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/cart.tsx
@@ -1,39 +1,12 @@
-import {
- Cart as CartController,
- CartItem,
- CartState,
- ContextState,
- Context as ContextController,
-} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
-import {formatCurrency} from '../_utils/format-currency';
+'use client';
-interface CartProps {
- staticState: CartState;
- controller?: CartController;
- staticContextState: ContextState;
- contextController?: ContextController;
-}
+import {CartItem} from '@coveo/headless-react/ssr-commerce';
+import {useCart, useContext} from '../_lib/commerce-engine';
+import {formatCurrency} from '../_utils/format-currency';
-export default function Cart({
- staticState,
- controller,
- staticContextState,
- contextController,
-}: CartProps) {
- const [state, setState] = useState(staticState);
- useEffect(
- () => controller?.subscribe(() => setState({...controller.state})),
- [controller]
- );
- const [contextState, setContextState] = useState(staticContextState);
- useEffect(
- () =>
- contextController?.subscribe(() =>
- setContextState({...contextController.state})
- ),
- [contextController]
- );
+export default function Cart() {
+ const {state, controller} = useCart();
+ const {state: contextState} = useContext();
const adjustQuantity = (item: CartItem, delta: number) => {
controller?.updateItemQuantity({
diff --git a/packages/samples/headless-ssr-commerce/app/_components/facets/category-facet.tsx b/packages/samples/headless-ssr-commerce/app/_components/facets/category-facet.tsx
index 90c499d7629..418cbf91593 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/facets/category-facet.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/facets/category-facet.tsx
@@ -1,9 +1,11 @@
+'use client';
+
import {
CategoryFacetSearchResult,
CategoryFacetState,
CategoryFacetValue,
CategoryFacet as HeadlessCategoryFacet,
-} from '@coveo/headless/ssr-commerce';
+} from '@coveo/headless-react/ssr-commerce';
import {useEffect, useRef, useState} from 'react';
interface ICategoryFacetProps {
diff --git a/packages/samples/headless-ssr-commerce/app/_components/facets/date-facet.tsx b/packages/samples/headless-ssr-commerce/app/_components/facets/date-facet.tsx
index e6e944c7148..1541bbda894 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/facets/date-facet.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/facets/date-facet.tsx
@@ -1,7 +1,9 @@
+'use client';
+
import {
DateFacetState,
DateFacet as HeadlessDateFacet,
-} from '@coveo/headless/ssr-commerce';
+} from '@coveo/headless-react/ssr-commerce';
import {useEffect, useState} from 'react';
interface IDateFacetProps {
diff --git a/packages/samples/headless-ssr-commerce/app/_components/facets/facet-generator.tsx b/packages/samples/headless-ssr-commerce/app/_components/facets/facet-generator.tsx
index 4c0ce296bf0..0d6dcbb26bf 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/facets/facet-generator.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/facets/facet-generator.tsx
@@ -1,28 +1,13 @@
-import {
- FacetGenerator as HeadlessFacetGenerator,
- FacetGeneratorState,
-} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
+'use client';
+
+import {useFacetGenerator} from '@/app/_lib/commerce-engine';
import CategoryFacet from './category-facet';
import DateFacet from './date-facet';
import NumericFacet from './numeric-facet';
import RegularFacet from './regular-facet';
-interface IFacetGeneratorProps {
- controller?: HeadlessFacetGenerator;
- staticState: FacetGeneratorState;
-}
-
-export default function FacetGenerator(props: IFacetGeneratorProps) {
- const {controller, staticState} = props;
-
- const [state, setState] = useState(staticState);
-
- useEffect(() => {
- controller?.subscribe(() => {
- setState(controller.state);
- });
- }, [controller]);
+export default function FacetGenerator() {
+ const {state, controller} = useFacetGenerator();
return (
diff --git a/packages/samples/headless-ssr-commerce/app/_components/facets/numeric-facet.tsx b/packages/samples/headless-ssr-commerce/app/_components/facets/numeric-facet.tsx
index 7de9f474815..743edb8157d 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/facets/numeric-facet.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/facets/numeric-facet.tsx
@@ -1,7 +1,9 @@
+'use client';
+
import {
NumericFacet as HeadlessNumericFacet,
NumericFacetState,
-} from '@coveo/headless/ssr-commerce';
+} from '@coveo/headless-react/ssr-commerce';
import {useEffect, useRef, useState} from 'react';
interface INumericFacetProps {
diff --git a/packages/samples/headless-ssr-commerce/app/_components/facets/regular-facet.tsx b/packages/samples/headless-ssr-commerce/app/_components/facets/regular-facet.tsx
index c071b865cbb..f7f19df39a5 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/facets/regular-facet.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/facets/regular-facet.tsx
@@ -1,9 +1,11 @@
+'use client';
+
import {
BaseFacetSearchResult,
RegularFacet as HeadlessRegularFacet,
RegularFacetState,
RegularFacetValue,
-} from '@coveo/headless/ssr-commerce';
+} from '@coveo/headless-react/ssr-commerce';
import {useEffect, useRef, useState} from 'react';
interface IRegularFacetProps {
diff --git a/packages/samples/headless-ssr-commerce/app/_components/instant-product.tsx b/packages/samples/headless-ssr-commerce/app/_components/instant-product.tsx
index 8b21b870605..87f184b7e7c 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/instant-product.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/instant-product.tsx
@@ -1,31 +1,11 @@
-import {
- InstantProductsState,
- InstantProducts as InstantProductsController,
- Product,
-} from '@coveo/headless/ssr-commerce';
+import {Product} from '@coveo/headless-react/ssr-commerce';
import {useRouter} from 'next/navigation';
-import {useEffect, useState} from 'react';
+import {useInstantProducts} from '../_lib/commerce-engine';
-interface InstantProductsProps {
- staticState: InstantProductsState;
- controller?: InstantProductsController;
-}
-
-export default function InstantProducts({
- staticState,
- controller,
-}: InstantProductsProps) {
+export default function InstantProducts() {
const router = useRouter();
- const [state, setState] = useState(staticState);
-
- useEffect(
- () =>
- controller?.subscribe(() => {
- setState({...controller.state});
- }),
- [controller]
- );
+ const {state, controller} = useInstantProducts();
const clickProduct = (product: Product) => {
controller?.interactiveProduct({options: {product}}).select();
diff --git a/packages/samples/headless-ssr-commerce/app/_components/pages/listing-page.tsx b/packages/samples/headless-ssr-commerce/app/_components/pages/listing-page.tsx
index 05612968ed2..4cfc2e95754 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/pages/listing-page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/pages/listing-page.tsx
@@ -1,29 +1,23 @@
'use client';
-import {NavigatorContext} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
+import {NavigatorContext} from '@coveo/headless-react/ssr-commerce';
+import {PropsWithChildren, useEffect, useState} from 'react';
import {
listingEngineDefinition,
ListingHydratedState,
ListingStaticState,
} from '../../_lib/commerce-engine';
-import BreadcrumbManager from '../breadcrumb-manager';
-import Cart from '../cart';
-import FacetGenerator from '../facets/facet-generator';
-import Pagination from '../pagination';
-import ProductList from '../product-list';
-import {Recommendations} from '../recommendation-list';
-import Sort from '../sort';
-import StandaloneSearchBox from '../standalone-search-box';
-import Summary from '../summary';
+
+interface ListingPageProps {
+ staticState: ListingStaticState;
+ navigatorContext: NavigatorContext;
+}
export default function ListingPage({
staticState,
navigatorContext,
-}: {
- staticState: ListingStaticState;
- navigatorContext: NavigatorContext;
-}) {
+ children,
+}: PropsWithChildren) {
const [hydratedState, setHydratedState] = useState<
ListingHydratedState | undefined
>(undefined);
@@ -40,78 +34,28 @@ export default function ListingPage({
setHydratedState({engine, controllers});
// Refreshing recommendations in the browser after hydrating the state in the client-side
// Recommendation refresh in the server is not supported yet.
- controllers.popularBoughtRecs.refresh();
+ // controllers.popularBoughtRecs.refresh(); // FIXME: does not work
});
}, [staticState]);
- return (
- <>
-
-
-
-
-
-
-
-
- {/* The ShowMore and Pagination components showcase two frequent ways to implement pagination. */}
-
- {/*
*/}
-
-
-
-
My Cart
-
-
-
-
-
-
-
- >
- );
+ if (hydratedState) {
+ return (
+
+ <>{children}>
+
+ );
+ } else {
+ return (
+
+ {/* // TODO: FIXME: Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react/index").ReactNode'.
+ Type 'bigint' is not assignable to type 'ReactNode'.*/}
+ <>{children}>
+
+ );
+ }
}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/pages/product-page.tsx b/packages/samples/headless-ssr-commerce/app/_components/pages/product-page.tsx
index d964f2b9b08..0cb4ea535c0 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/pages/product-page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/pages/product-page.tsx
@@ -5,7 +5,7 @@ import {
StandaloneHydratedState,
StandaloneStaticState,
} from '@/app/_lib/commerce-engine';
-import {NavigatorContext} from '@coveo/headless/ssr-commerce';
+import {NavigatorContext} from '@coveo/headless-react/ssr-commerce';
import {useSearchParams} from 'next/navigation';
import {useEffect, useState} from 'react';
import {Recommendations} from '../recommendation-list';
@@ -59,10 +59,7 @@ export default function ProductPage(props: IProductPageProps) {
{name} ({productId}) - ${price}
-
+
>
);
}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/pages/recommendation.tsx b/packages/samples/headless-ssr-commerce/app/_components/pages/recommendation.tsx
deleted file mode 100644
index 55d7ce66d52..00000000000
--- a/packages/samples/headless-ssr-commerce/app/_components/pages/recommendation.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-'use client';
-
-import {NavigatorContext} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
-import {
- StandaloneStaticState,
- StandaloneHydratedState,
- standaloneEngineDefinition,
-} from '../../_lib/commerce-engine';
-import {Recommendations} from '../recommendation-list';
-
-export default function Recommendation({
- staticState,
- navigatorContext,
-}: {
- staticState: StandaloneStaticState;
- navigatorContext: NavigatorContext;
-}) {
- const [hydratedState, setHydratedState] = useState<
- StandaloneHydratedState | undefined
- >(undefined);
-
- // Setting the navigator context provider also in client-side before hydrating the application
- standaloneEngineDefinition.setNavigatorContextProvider(
- () => navigatorContext
- );
-
- useEffect(() => {
- standaloneEngineDefinition
- .hydrateStaticState({
- searchAction: staticState.searchAction,
- })
- .then(({engine, controllers}) => {
- setHydratedState({engine, controllers});
-
- // Refreshing recommendations in the browser after hydrating the state in the client-side
- // Recommendation refresh in the server is not supported yet.
- controllers.popularBoughtRecs.refresh();
- controllers.popularViewedRecs.refresh();
- });
- }, [staticState]);
-
- return (
- <>
-
-
- >
- );
-}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/pages/search-page.tsx b/packages/samples/headless-ssr-commerce/app/_components/pages/search-page.tsx
index 3e5d7644bcb..1b07385a4d1 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/pages/search-page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/pages/search-page.tsx
@@ -1,28 +1,23 @@
'use client';
-import {NavigatorContext} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
+import {NavigatorContext} from '@coveo/headless-react/ssr-commerce';
+import {PropsWithChildren, useEffect, useState} from 'react';
import {
SearchHydratedState,
SearchStaticState,
searchEngineDefinition,
} from '../../_lib/commerce-engine';
-import BreadcrumbManager from '../breadcrumb-manager';
-import FacetGenerator from '../facets/facet-generator';
-import ProductList from '../product-list';
-import {Recommendations} from '../recommendation-list';
-import SearchBox from '../search-box';
-import ShowMore from '../show-more';
-import Summary from '../summary';
-import Triggers from '../triggers/triggers';
+
+interface SearchPageProps {
+ staticState: SearchStaticState;
+ navigatorContext: NavigatorContext;
+}
export default function SearchPage({
staticState,
navigatorContext,
-}: {
- staticState: SearchStaticState;
- navigatorContext: NavigatorContext;
-}) {
+ children,
+}: PropsWithChildren) {
const [hydratedState, setHydratedState] = useState<
SearchHydratedState | undefined
>(undefined);
@@ -40,77 +35,30 @@ export default function SearchPage({
// Refreshing recommendations in the browser after hydrating the state in the client-side
// Recommendation refresh in the server is not supported yet.
- controllers.popularBoughtRecs.refresh();
+ // controllers.popularBoughtRecs.refresh();
});
}, [staticState]);
- return (
- <>
-
-
-
-
-
-
-
-
- {/* The ShowMore and Pagination components showcase two frequent ways to implement pagination. */}
- {/*
*/}
-
-
-
-
-
-
-
- >
- );
+ if (hydratedState) {
+ return (
+
+ {/* // TODO: FIXME: Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react/index").ReactNode'.
+ Type 'bigint' is not assignable to type 'ReactNode'.*/}
+ <>{children}>
+
+ );
+ } else {
+ return (
+
+ {/* // TODO: FIXME: Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react/index").ReactNode'.
+ Type 'bigint' is not assignable to type 'ReactNode'.*/}
+ <>{children}>
+
+ );
+ }
}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/pagination.tsx b/packages/samples/headless-ssr-commerce/app/_components/pagination.tsx
index c2e25737725..b8acfd7bb27 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/pagination.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/pagination.tsx
@@ -1,22 +1,9 @@
-import {
- Pagination as HeadlessPagination,
- PaginationState,
-} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
+'use client';
-interface IPaginationProps {
- staticState: PaginationState;
- controller?: HeadlessPagination;
-}
-
-export default function Pagination(props: IPaginationProps) {
- const {staticState, controller} = props;
-
- const [state, setState] = useState(staticState);
+import {usePagination} from '../_lib/commerce-engine';
- useEffect(() => {
- controller?.subscribe(() => setState(controller.state));
- }, [controller]);
+export default function Pagination() {
+ const {state, controller} = usePagination();
const renderPageRadioButtons = () => {
return Array.from({length: state.totalPages}, (_, i) => {
diff --git a/packages/samples/headless-ssr-commerce/app/_components/product-list.tsx b/packages/samples/headless-ssr-commerce/app/_components/product-list.tsx
index e9f3464cdca..8c5b9a6701e 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/product-list.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/product-list.tsx
@@ -1,29 +1,14 @@
-import {
- Product,
- ProductList as ProductListingController,
- ProductListState,
-} from '@coveo/headless/ssr-commerce';
-import {useRouter} from 'next/navigation';
-import {useEffect, useState} from 'react';
+'use client';
-interface ProductListProps {
- staticState: ProductListState;
- controller?: ProductListingController;
-}
+import {Product} from '@coveo/headless-react/ssr-commerce';
+import {useRouter} from 'next/navigation';
+import {useProductList} from '../_lib/commerce-engine';
-export default function ProductList({
- staticState,
- controller,
-}: ProductListProps) {
- const [state, setState] = useState(staticState);
+export default function ProductList() {
+ const {state, controller} = useProductList();
const router = useRouter();
- useEffect(
- () => controller?.subscribe(() => setState({...controller.state})),
- [controller]
- );
-
const onProductClick = (product: Product) => {
controller?.interactiveProduct({options: {product}}).select();
router.push(
diff --git a/packages/samples/headless-ssr-commerce/app/_components/recent-queries.tsx b/packages/samples/headless-ssr-commerce/app/_components/recent-queries.tsx
index 3893d5f4cb0..323b4cfb62e 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/recent-queries.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/recent-queries.tsx
@@ -1,26 +1,11 @@
import {
- RecentQueriesState,
- RecentQueriesList as RecentQueriesController,
- InstantProducts as InstantProductsController,
-} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
+ useInstantProducts,
+ useRecentQueriesList,
+} from '../_lib/commerce-engine';
-interface RecentQueriesProps {
- staticState: RecentQueriesState;
- controller?: RecentQueriesController;
- instantProductsController?: InstantProductsController;
-}
-
-export default function RecentQueries({
- staticState,
- controller,
- instantProductsController,
-}: RecentQueriesProps) {
- const [state, setState] = useState(staticState);
-
- useEffect(() => {
- controller?.subscribe(() => setState({...controller.state}));
- }, [controller]);
+export default function RecentQueries() {
+ const {state, controller} = useRecentQueriesList();
+ const {controller: instantProductsController} = useInstantProducts();
return (
diff --git a/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx b/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
index 944f4401fa4..3c3166ae173 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
@@ -1,29 +1,17 @@
-import {
- Product,
- Recommendations as RecommendationsController,
- RecommendationsState,
-} from '@coveo/headless/ssr-commerce';
-import {useRouter} from 'next/navigation';
-import {useEffect, useState, FunctionComponent} from 'react';
+'use client';
-interface RecommendationsProps {
- staticState: RecommendationsState;
- controller?: RecommendationsController;
-}
+import {Product} from '@coveo/headless-react/ssr-commerce';
+import {useRouter} from 'next/navigation';
+import {FunctionComponent} from 'react';
+import {usePopularBoughtRecs} from '../_lib/commerce-engine';
-export const Recommendations: FunctionComponent
= ({
- staticState,
- controller,
-}) => {
- const [state, setState] = useState(staticState);
+export const Recommendations: FunctionComponent = () => {
+ // TODO: find a way to make the recommendation generic
+ const {state, controller} = usePopularBoughtRecs();
+ // TODO: recommendation are not refreshed server-side FIXME:
const router = useRouter();
- useEffect(
- () => controller?.subscribe(() => setState({...controller.state})),
- [controller]
- );
-
const onProductClick = (product: Product) => {
controller?.interactiveProduct({options: {product}}).select();
router.push(
diff --git a/packages/samples/headless-ssr-commerce/app/_components/search-box.tsx b/packages/samples/headless-ssr-commerce/app/_components/search-box.tsx
index ea04fdaeca4..8926119fc4b 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/search-box.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/search-box.tsx
@@ -1,52 +1,23 @@
+'use client';
+
+import {useState} from 'react';
import {
- SearchBoxState,
- SearchBox as SearchBoxController,
- RecentQueriesList as RecentQueriesListController,
- RecentQueriesState,
- InstantProductsState,
- InstantProducts as InstantProductsController,
-} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
+ useInstantProducts,
+ useRecentQueriesList,
+ useSearchBox,
+} from '../_lib/commerce-engine';
import InstantProducts from './instant-product';
import RecentQueries from './recent-queries';
-interface SearchBoxProps {
- staticState: SearchBoxState;
- controller?: SearchBoxController;
- staticStateRecentQueries: RecentQueriesState;
- recentQueriesController?: RecentQueriesListController;
- staticStateInstantProducts: InstantProductsState;
- instantProductsController?: InstantProductsController;
-}
+export default function SearchBox() {
+ const {state, controller} = useSearchBox();
+ const {state: recentQueriesState} = useRecentQueriesList();
+ const {state: instantProductsState, controller: instantProductsController} =
+ useInstantProducts();
-export default function SearchBox({
- staticState,
- controller,
- staticStateRecentQueries,
- recentQueriesController,
- staticStateInstantProducts,
- instantProductsController,
-}: SearchBoxProps) {
- const [state, setState] = useState(staticState);
- const [recentQueriesState, setRecentQueriesState] = useState(
- staticStateRecentQueries
- );
- const [instantProductsState, setInstantProductsState] = useState(
- staticStateInstantProducts
- );
const [isInputFocused, setIsInputFocused] = useState(false);
const [isSelectingSuggestion, setIsSelectingSuggestion] = useState(false);
- useEffect(() => {
- controller?.subscribe(() => setState({...controller.state}));
- recentQueriesController?.subscribe(() =>
- setRecentQueriesState({...recentQueriesController.state})
- );
- instantProductsController?.subscribe(() =>
- setInstantProductsState({...instantProductsController.state})
- );
- }, [controller, instantProductsController, recentQueriesController]);
-
const onSearchBoxInputChange = (e: React.ChangeEvent) => {
setIsSelectingSuggestion(true);
controller?.updateText(e.target.value);
@@ -80,13 +51,7 @@ export default function SearchBox({
{isInputFocused && (
<>
- {recentQueriesState.queries.length > 0 && (
-
- )}
+ {recentQueriesState.queries.length > 0 && }
{state.suggestions.length > 0 && (
Suggestions :
@@ -109,12 +74,7 @@ export default function SearchBox({
))}
)}
- {instantProductsState.products.length > 0 && (
-
- )}
+ {instantProductsState.products.length > 0 && }
>
)}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/show-more.tsx b/packages/samples/headless-ssr-commerce/app/_components/show-more.tsx
index 5ba95e57d8f..e3bb103b18f 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/show-more.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/show-more.tsx
@@ -1,33 +1,10 @@
-import {
- Pagination as HeadlessPagination,
- PaginationState,
- Summary,
-} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
+'use client';
-interface IShowMoreProps {
- staticState: PaginationState;
- summaryController?: Summary;
- controller?: HeadlessPagination;
-}
-
-export default function ShowMore(props: IShowMoreProps) {
- const {controller, summaryController, staticState} = props;
-
- const [state, setState] = useState(staticState);
- const [summaryState, setSummaryState] = useState(
- props.summaryController?.state
- );
-
- useEffect(() => {
- controller?.subscribe(() => setState(controller.state));
- }, [controller]);
+import {usePagination, useSummary} from '../_lib/commerce-engine';
- useEffect(() => {
- summaryController?.subscribe(() =>
- setSummaryState(summaryController.state)
- );
- }, [summaryController]);
+export default function ShowMore() {
+ const {state, controller} = usePagination();
+ const {state: summaryState} = useSummary();
const handleFetchMore = () => {
controller?.fetchMoreProducts();
diff --git a/packages/samples/headless-ssr-commerce/app/_components/sort.tsx b/packages/samples/headless-ssr-commerce/app/_components/sort.tsx
index c0f0d661adb..796b2656933 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/sort.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/sort.tsx
@@ -1,37 +1,23 @@
-import {SortState} from '@coveo/headless/commerce';
-import {
- Sort as HeadlessSort,
- SortBy,
- SortCriterion,
-} from '@coveo/headless/commerce';
-import {useEffect, useState} from 'react';
+'use client';
-interface ISortProps {
- controller?: HeadlessSort;
- staticState: SortState;
-}
-
-export default function Sort(props: ISortProps) {
- const {controller, staticState} = props;
-
- const [state, setState] = useState({...staticState});
+// import {SortBy, SortCriterion} from '@coveo/headless-react/ssr-commerce';
+import {useSort} from '../_lib/commerce-engine';
- useEffect(() => {
- controller?.subscribe(() => setState(controller.state));
- }, [controller]);
+export default function Sort() {
+ const {state, controller} = useSort();
if (state.availableSorts.length === 0) {
return null;
}
- const getSortLabel = (criterion: SortCriterion) => {
- switch (criterion.by) {
- case SortBy.Relevance:
- return 'Relevance';
- case SortBy.Fields:
- return criterion.fields.map((field) => field.displayName).join(', ');
- }
- };
+ // const getSortLabel = (criterion: SortCriterion) => {
+ // switch (criterion.by) {
+ // case SortBy.Relevancy:
+ // return 'Relevance';
+ // case SortBy.Field:
+ // return criterion.field;
+ // }
+ // };
return (
@@ -49,7 +35,8 @@ export default function Sort(props: ISortProps) {
value={JSON.stringify(sort)}
onSelect={() => controller?.sortBy(sort)}
>
- {getSortLabel(sort)}
+ {/* TODO: there is a type mismatch with the sort criterion FIXME:!!*/}
+ {/* {getSortLabel(sort)} */}
))}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/standalone-search-box.tsx b/packages/samples/headless-ssr-commerce/app/_components/standalone-search-box.tsx
index 24516f0764f..5e7b1d61f9a 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/standalone-search-box.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/standalone-search-box.tsx
@@ -1,52 +1,24 @@
-import {
- StandaloneSearchBoxState,
- StandaloneSearchBox as StandaloneSearchBoxController,
- RecentQueriesState,
- InstantProductsState,
- RecentQueriesList as RecentQueriesListController,
- InstantProducts as InstantProductsController,
-} from '@coveo/headless/ssr-commerce';
+'use client';
+
import {useRouter} from 'next/navigation';
import {useEffect, useState} from 'react';
+import {
+ useInstantProducts,
+ useRecentQueriesList,
+ useStandaloneSearchBox,
+} from '../_lib/commerce-engine';
import InstantProducts from './instant-product';
import RecentQueries from './recent-queries';
-interface StandaloneSearchBoxProps {
- staticState: StandaloneSearchBoxState;
- controller?: StandaloneSearchBoxController;
- staticStateRecentQueries: RecentQueriesState;
- recentQueriesController?: RecentQueriesListController;
- staticStateInstantProducts: InstantProductsState;
- instantProductsController?: InstantProductsController;
-}
+export default function StandaloneSearchBox() {
+ const {state, controller} = useStandaloneSearchBox();
+ const {state: recentQueriesState} = useRecentQueriesList();
+ const {state: instantProductsState, controller: instantProductsController} =
+ useInstantProducts();
-export default function StandaloneSearchBox({
- staticState,
- controller,
- staticStateRecentQueries,
- recentQueriesController,
- staticStateInstantProducts,
- instantProductsController,
-}: StandaloneSearchBoxProps) {
- const [state, setState] = useState(staticState);
- const [recentQueriesState, setRecentQueriesState] = useState(
- staticStateRecentQueries
- );
- const [instantProductsState, setInstantProductsState] = useState(
- staticStateInstantProducts
- );
const [isInputFocused, setIsInputFocused] = useState(false);
const [isSelectingSuggestion, setIsSelectingSuggestion] = useState(false);
- useEffect(() => {
- controller?.subscribe(() => setState({...controller.state}));
- recentQueriesController?.subscribe(() =>
- setRecentQueriesState({...recentQueriesController.state})
- );
- instantProductsController?.subscribe(() =>
- setInstantProductsState({...instantProductsController.state})
- );
- }, [controller, instantProductsController, recentQueriesController]);
const router = useRouter();
useEffect(() => {
@@ -90,13 +62,7 @@ export default function StandaloneSearchBox({
{isInputFocused && (
<>
- {recentQueriesState.queries.length > 0 && (
-
- )}
+ {recentQueriesState.queries.length > 0 &&
}
{state.suggestions.length > 0 && (
Suggestions :
@@ -119,12 +85,7 @@ export default function StandaloneSearchBox({
))}
)}
- {instantProductsState.products.length > 0 && (
-
- )}
+ {instantProductsState.products.length > 0 &&
}
>
)}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/summary.tsx b/packages/samples/headless-ssr-commerce/app/_components/summary.tsx
index f267bca3300..887f6d26182 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/summary.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/summary.tsx
@@ -1,27 +1,9 @@
-import {
- Summary as HeadlessSummary,
- ProductListingSummaryState,
- SearchSummaryState,
- RecommendationsSummaryState,
-} from '@coveo/headless/ssr-commerce';
-import {useEffect, useState} from 'react';
+'use client';
-interface ISummaryProps {
- controller?: HeadlessSummary;
- staticState:
- | ProductListingSummaryState
- | SearchSummaryState
- | RecommendationsSummaryState;
-}
-
-export default function Summary(props: ISummaryProps) {
- const {controller, staticState} = props;
+import {useSummary} from '../_lib/commerce-engine';
- const [state, setState] = useState(staticState);
-
- useEffect(() => {
- controller?.subscribe(() => setState(controller.state));
- }, [controller]);
+export default function Summary() {
+ const {state} = useSummary();
const renderBaseSummary = () => {
const {firstProduct, lastProduct, totalNumberOfProducts} = state;
@@ -38,11 +20,12 @@ export default function Summary(props: ISummaryProps) {
return null;
}
- return (
-
- for {state.query}
-
- );
+ // TODO: add query to summary state
+ // return (
+ //
+ // for {state.query}
+ //
+ // );
};
const renderSummary = () => {
diff --git a/packages/samples/headless-ssr-commerce/app/_components/triggers/notify-trigger.tsx b/packages/samples/headless-ssr-commerce/app/_components/triggers/notify-trigger.tsx
index 35cadb8a3d8..035e88d49ee 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/triggers/notify-trigger.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/triggers/notify-trigger.tsx
@@ -1,25 +1,11 @@
-import {
- NotifyTrigger as NotifyTriggerController,
- NotifyTriggerState,
-} from '@coveo/headless/commerce';
-import {useCallback, useEffect, useState} from 'react';
+'use client';
-interface NotifyTriggerProps {
- controller?: NotifyTriggerController;
- staticState: NotifyTriggerState;
-}
+import {useNotifyTrigger} from '@/app/_lib/commerce-engine';
+import {useCallback, useEffect} from 'react';
// The notify trigger query example in the searchuisamples org is 'notify me'.
-export default function NotifyTrigger({
- controller,
- staticState,
-}: NotifyTriggerProps) {
- const [state, setState] = useState(staticState);
-
- useEffect(
- () => controller?.subscribe(() => setState({...controller.state})),
- [controller]
- );
+export default function NotifyTrigger() {
+ const {state} = useNotifyTrigger();
const notify = useCallback(() => {
state.notifications.forEach((notification) => {
diff --git a/packages/samples/headless-ssr-commerce/app/_components/triggers/query-trigger.tsx b/packages/samples/headless-ssr-commerce/app/_components/triggers/query-trigger.tsx
index 01fe1a061af..9b052460347 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/triggers/query-trigger.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/triggers/query-trigger.tsx
@@ -1,25 +1,10 @@
-import {
- QueryTrigger as QueryTriggerController,
- QueryTriggerState,
-} from '@coveo/headless/commerce';
-import {useEffect, useState} from 'react';
+'use client';
-interface QueryTriggerProps {
- controller?: QueryTriggerController;
- staticState: QueryTriggerState;
-}
+import {useQueryTrigger} from '@/app/_lib/commerce-engine';
// The query trigger query example in the searchuisamples org is 'query me'.
-export default function QueryTrigger({
- controller,
- staticState,
-}: QueryTriggerProps) {
- const [state, setState] = useState(staticState);
-
- useEffect(
- () => controller?.subscribe(() => setState({...controller.state})),
- [controller]
- );
+export default function QueryTrigger() {
+ const {state} = useQueryTrigger();
if (state.wasQueryModified) {
return (
diff --git a/packages/samples/headless-ssr-commerce/app/_components/triggers/redirection-trigger.tsx b/packages/samples/headless-ssr-commerce/app/_components/triggers/redirection-trigger.tsx
index 38455192d35..f97f7992407 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/triggers/redirection-trigger.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/triggers/redirection-trigger.tsx
@@ -1,25 +1,11 @@
-import {
- RedirectionTrigger as RedirectionTriggerController,
- RedirectionTriggerState,
-} from '@coveo/headless/commerce';
-import {useCallback, useEffect, useState} from 'react';
+'use client';
-interface RedirectionTriggerProps {
- controller?: RedirectionTriggerController;
- staticState: RedirectionTriggerState;
-}
+import {useRedirectionTrigger} from '@/app/_lib/commerce-engine';
+import {useCallback, useEffect} from 'react';
// The redirection trigger query example in the searchuisamples org is 'redirect me'.
-export default function RedirectionTrigger({
- controller,
- staticState,
-}: RedirectionTriggerProps) {
- const [state, setState] = useState(staticState);
-
- useEffect(
- () => controller?.subscribe(() => setState({...controller.state})),
- [controller]
- );
+export default function RedirectionTrigger() {
+ const {state} = useRedirectionTrigger();
const redirect = useCallback(() => {
if (state.redirectTo) {
diff --git a/packages/samples/headless-ssr-commerce/app/_components/triggers/triggers.tsx b/packages/samples/headless-ssr-commerce/app/_components/triggers/triggers.tsx
index 8086cede817..6ac0b54befa 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/triggers/triggers.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/triggers/triggers.tsx
@@ -1,45 +1,13 @@
-import {
- QueryTrigger as QueryTriggerController,
- QueryTriggerState,
- RedirectionTrigger as RedirectionTriggerController,
- RedirectionTriggerState,
- NotifyTrigger as NotifyTriggerController,
- NotifyTriggerState,
-} from '@coveo/headless/commerce';
import NotifyTrigger from './notify-trigger';
import QueryTrigger from './query-trigger';
import RedirectionTrigger from './redirection-trigger';
-interface TriggersProps {
- redirectionController?: RedirectionTriggerController;
- redirectionStaticState: RedirectionTriggerState;
- queryDontroller?: QueryTriggerController;
- queryStaticState: QueryTriggerState;
- notifyController?: NotifyTriggerController;
- notifyStaticState: NotifyTriggerState;
-}
-export default function Triggers({
- redirectionStaticState,
- redirectionController,
- queryStaticState,
- queryDontroller,
- notifyStaticState,
- notifyController,
-}: TriggersProps) {
+export default function Triggers() {
return (
<>
-
-
-
+
+
+
>
);
}
diff --git a/packages/samples/headless-ssr-commerce/app/_lib/commerce-engine-config.ts b/packages/samples/headless-ssr-commerce/app/_lib/commerce-engine-config.ts
index ce281375e97..4a02e7b0287 100644
--- a/packages/samples/headless-ssr-commerce/app/_lib/commerce-engine-config.ts
+++ b/packages/samples/headless-ssr-commerce/app/_lib/commerce-engine-config.ts
@@ -13,6 +13,7 @@ import {
defineRedirectionTrigger,
defineStandaloneSearchBox,
defineInstantProducts,
+ defineBreadcrumbManager,
defineSummary,
definePagination,
defineFacetGenerator,
@@ -21,8 +22,7 @@ import {
getSampleCommerceEngineConfiguration,
defineDidYouMean,
defineRecommendations, //defineParameterManager,
- defineBreadcrumbManager,
-} from '@coveo/headless/ssr-commerce';
+} from '@coveo/headless-react/ssr-commerce';
type CommerceEngineConfig = CommerceEngineDefinitionOptions<
ControllerDefinitionsMap
diff --git a/packages/samples/headless-ssr-commerce/app/_lib/commerce-engine.ts b/packages/samples/headless-ssr-commerce/app/_lib/commerce-engine.ts
index 0d08774ac59..91ea7d56473 100644
--- a/packages/samples/headless-ssr-commerce/app/_lib/commerce-engine.ts
+++ b/packages/samples/headless-ssr-commerce/app/_lib/commerce-engine.ts
@@ -2,17 +2,40 @@ import {
defineCommerceEngine,
InferStaticState,
InferHydratedState,
-} from '@coveo/headless/ssr-commerce';
+} from '@coveo/headless-react/ssr-commerce';
import engineConfig from './commerce-engine-config';
-const engineDefinition = defineCommerceEngine(engineConfig);
+export const engineDefinition = defineCommerceEngine(engineConfig);
export const {
listingEngineDefinition,
searchEngineDefinition,
standaloneEngineDefinition,
+ useEngine,
} = engineDefinition;
+export const {
+ useCart,
+ useContext,
+ useProductList,
+ useDidYouMean,
+ useInstantProducts,
+ useNotifyTrigger,
+ usePagination,
+ usePopularBoughtRecs,
+ usePopularViewedRecs,
+ useProductView,
+ useQueryTrigger,
+ useRecentQueriesList,
+ useRedirectionTrigger,
+ useSearchBox,
+ useSort,
+ useStandaloneSearchBox,
+ useSummary,
+ useFacetGenerator,
+ useBreadcrumbManager,
+} = engineDefinition.controllers;
+
export type ListingStaticState = InferStaticState<
typeof listingEngineDefinition
>;
diff --git a/packages/samples/headless-ssr-commerce/app/_lib/navigatorContextProvider.ts b/packages/samples/headless-ssr-commerce/app/_lib/navigatorContextProvider.ts
index cb5ffa03b7e..47921af03fc 100644
--- a/packages/samples/headless-ssr-commerce/app/_lib/navigatorContextProvider.ts
+++ b/packages/samples/headless-ssr-commerce/app/_lib/navigatorContextProvider.ts
@@ -1,4 +1,4 @@
-import {NavigatorContext} from '@coveo/headless/ssr-commerce';
+import {NavigatorContext} from '@coveo/headless-react/ssr-commerce';
import type {ReadonlyHeaders} from 'next/dist/server/web/spec-extension/adapters/headers';
/**
diff --git a/packages/samples/headless-ssr-commerce/app/layout.tsx b/packages/samples/headless-ssr-commerce/app/layout.tsx
index 63a608acbe9..e1db209ed3c 100644
--- a/packages/samples/headless-ssr-commerce/app/layout.tsx
+++ b/packages/samples/headless-ssr-commerce/app/layout.tsx
@@ -2,8 +2,7 @@ import Link from 'next/link';
export const metadata = {
title: 'Headless SSR examples',
- description:
- 'Examples of using framework agnostic @coveo/headless/ssr-commerce',
+ description: 'Examples of using framework @coveo/headless-react/ssr-commerce',
};
export default function RootLayout({children}: {children: React.ReactNode}) {
diff --git a/packages/samples/headless-ssr-commerce/app/listing/page.tsx b/packages/samples/headless-ssr-commerce/app/listing/page.tsx
index 1e6bfff2c94..e03abd76d59 100644
--- a/packages/samples/headless-ssr-commerce/app/listing/page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/listing/page.tsx
@@ -1,5 +1,14 @@
import {headers} from 'next/headers';
+import BreadcrumbManager from '../_components/breadcrumb-manager';
+import Cart from '../_components/cart';
+import FacetGenerator from '../_components/facets/facet-generator';
import ListingPage from '../_components/pages/listing-page';
+import Pagination from '../_components/pagination';
+import ProductList from '../_components/product-list';
+import {Recommendations} from '../_components/recommendation-list';
+import Sort from '../_components/sort';
+import StandaloneSearchBox from '../_components/standalone-search-box';
+import Summary from '../_components/summary';
import {listingEngineDefinition} from '../_lib/commerce-engine';
import {NextJsNavigatorContext} from '../_lib/navigatorContextProvider';
@@ -20,7 +29,34 @@ export default async function Listing() {
+ >
+
+
+
+
+
+
+
+
+ {/* The ShowMore and Pagination components showcase two frequent ways to implement pagination. */}
+
+ {/*
*/}
+
+
+
+
My Cart
+
+
+
+
+
+
+
+
);
}
diff --git a/packages/samples/headless-ssr-commerce/app/recommendation/page.tsx b/packages/samples/headless-ssr-commerce/app/recommendation/page.tsx
deleted file mode 100644
index 3a27fdbfe0f..00000000000
--- a/packages/samples/headless-ssr-commerce/app/recommendation/page.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import {headers} from 'next/headers';
-import Recommendation from '../_components/pages/recommendation';
-import {standaloneEngineDefinition} from '../_lib/commerce-engine';
-import {NextJsNavigatorContext} from '../_lib/navigatorContextProvider';
-
-/**
- * This file defines a List component that uses the Coveo Headless SSR commerce library to manage its state.
- *
- * The Listing function is the entry point for server-side rendering (SSR).
- */
-export default async function RecommendationPage() {
- // Sets the navigator context provider to use the newly created `navigatorContext` before fetching the app static state
- const navigatorContext = new NextJsNavigatorContext(headers());
- standaloneEngineDefinition.setNavigatorContextProvider(
- () => navigatorContext
- );
-
- // Fetches the static state of the app with initial state (when applicable)
- const staticState = await standaloneEngineDefinition.fetchStaticState();
-
- return (
-
- );
-}
-
-export const dynamic = 'force-dynamic';
diff --git a/packages/samples/headless-ssr-commerce/app/search/page.tsx b/packages/samples/headless-ssr-commerce/app/search/page.tsx
index 6c8a1a5c0a2..554898e951b 100644
--- a/packages/samples/headless-ssr-commerce/app/search/page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/search/page.tsx
@@ -1,5 +1,13 @@
import {headers} from 'next/headers';
+import BreadcrumbManager from '../_components/breadcrumb-manager';
+import FacetGenerator from '../_components/facets/facet-generator';
import SearchPage from '../_components/pages/search-page';
+import ProductList from '../_components/product-list';
+import {Recommendations} from '../_components/recommendation-list';
+import SearchBox from '../_components/search-box';
+import ShowMore from '../_components/show-more';
+import Summary from '../_components/summary';
+import Triggers from '../_components/triggers/triggers';
import {searchEngineDefinition} from '../_lib/commerce-engine';
import {NextJsNavigatorContext} from '../_lib/navigatorContextProvider';
@@ -14,7 +22,30 @@ export default async function Search() {
+ >
+
+
+
+
+
+
+
+
+ {/* The ShowMore and Pagination components showcase two frequent ways to implement pagination. */}
+ {/*
*/}
+
+
+
+
+ {/* popularBoughtRecs */}
+ {/* TODO: need to find a better way to target a recommendation slot id */}
+
+
+
+
);
}
diff --git a/packages/samples/headless-ssr-commerce/package.json b/packages/samples/headless-ssr-commerce/package.json
index 6fe3afc5e2f..2d2da69090e 100644
--- a/packages/samples/headless-ssr-commerce/package.json
+++ b/packages/samples/headless-ssr-commerce/package.json
@@ -1,6 +1,6 @@
{
"name": "@coveo/headless-ssr-commerce-samples",
- "description": "Examples of framework agnostic @coveo/headless/ssr-commerce utils using Next.js app router",
+ "description": "Examples of framework @coveo/headless-react/ssr-commerce utils using Next.js app router",
"version": "0.0.0",
"private": true,
"scripts": {
@@ -11,7 +11,7 @@
"build:next": "next build"
},
"dependencies": {
- "@coveo/headless": "3.5.0",
+ "@coveo/headless-react": "2.0.8",
"next": "14.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
From 868593c651fe9f500c0956b0974cbbeb81edce4f Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Thu, 31 Oct 2024 11:46:12 -0400
Subject: [PATCH 05/15] add todo
https://coveord.atlassian.net/browse/KIT-3699
---
.../samples/headless-ssr-commerce/app/_components/sort.tsx | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/samples/headless-ssr-commerce/app/_components/sort.tsx b/packages/samples/headless-ssr-commerce/app/_components/sort.tsx
index 796b2656933..e6db096652f 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/sort.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/sort.tsx
@@ -10,6 +10,7 @@ export default function Sort() {
return null;
}
+ // TODO: uncomment when KIT-3700: is fixed
// const getSortLabel = (criterion: SortCriterion) => {
// switch (criterion.by) {
// case SortBy.Relevancy:
@@ -35,7 +36,7 @@ export default function Sort() {
value={JSON.stringify(sort)}
onSelect={() => controller?.sortBy(sort)}
>
- {/* TODO: there is a type mismatch with the sort criterion FIXME:!!*/}
+ {/* TODO:KIT-3700: there is a type mismatch with the sort criterion FIXME:!!*/}
{/* {getSortLabel(sort)} */}
))}
From 3a376d7385123a9b053ee6e42d44228425ee18d1 Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Thu, 31 Oct 2024 11:50:50 -0400
Subject: [PATCH 06/15] add TODOs:
https://coveord.atlassian.net/browse/KIT-3699
---
.../app/_components/pages/search-page.tsx | 4 ++--
.../app/_components/recommendation-list.tsx | 3 +--
packages/samples/headless-ssr-commerce/app/search/page.tsx | 2 +-
3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/packages/samples/headless-ssr-commerce/app/_components/pages/search-page.tsx b/packages/samples/headless-ssr-commerce/app/_components/pages/search-page.tsx
index 1b07385a4d1..e67a82fa0a2 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/pages/search-page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/pages/search-page.tsx
@@ -45,7 +45,7 @@ export default function SearchPage({
engine={hydratedState.engine}
controllers={hydratedState.controllers}
>
- {/* // TODO: FIXME: Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react/index").ReactNode'.
+ {/* // TODO: KIT-3701: Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react/index").ReactNode'.
Type 'bigint' is not assignable to type 'ReactNode'.*/}
<>{children}>
@@ -55,7 +55,7 @@ export default function SearchPage({
- {/* // TODO: FIXME: Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react/index").ReactNode'.
+ {/* // TODO: KIT-3701: Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react/index").ReactNode'.
Type 'bigint' is not assignable to type 'ReactNode'.*/}
<>{children}>
diff --git a/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx b/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
index 3c3166ae173..5e71137880b 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
@@ -6,9 +6,8 @@ import {FunctionComponent} from 'react';
import {usePopularBoughtRecs} from '../_lib/commerce-engine';
export const Recommendations: FunctionComponent = () => {
- // TODO: find a way to make the recommendation generic
+ // TODO: KIT-3503: refresh recs server side
const {state, controller} = usePopularBoughtRecs();
- // TODO: recommendation are not refreshed server-side FIXME:
const router = useRouter();
diff --git a/packages/samples/headless-ssr-commerce/app/search/page.tsx b/packages/samples/headless-ssr-commerce/app/search/page.tsx
index 554898e951b..529e980932d 100644
--- a/packages/samples/headless-ssr-commerce/app/search/page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/search/page.tsx
@@ -41,7 +41,7 @@ export default async function Search() {
{/* popularBoughtRecs */}
- {/* TODO: need to find a better way to target a recommendation slot id */}
+ {/* TODO: KIT-3503: need to revisit the way recommendations are added*/}
From e43ef84e7ba76e15e2f48cd9ef4d78b1a262c0e3 Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Wed, 6 Nov 2024 15:13:48 -0500
Subject: [PATCH 07/15] Update packages/samples/headless-ssr-commerce/README.md
Co-authored-by: Frederic Beaudoin
---
packages/samples/headless-ssr-commerce/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/samples/headless-ssr-commerce/README.md b/packages/samples/headless-ssr-commerce/README.md
index e60a95e80e8..f2985117bfa 100644
--- a/packages/samples/headless-ssr-commerce/README.md
+++ b/packages/samples/headless-ssr-commerce/README.md
@@ -1,6 +1,6 @@
# Server side rendering examples
-- Demonstrates usage of the framework `@coveo/headless-react/ssr-commerce` utils for Server-Side Rendering with headless using Next.js in a commerce app.
+Demonstrates usage of the framework `@coveo/headless-react/ssr-commerce` utils for Server-Side Rendering with headless using Next.js in a commerce app.
## Getting Started
From ed8ef81f188b50ee64abe7c691f2cbb36da39ab7 Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Wed, 6 Nov 2024 15:14:24 -0500
Subject: [PATCH 08/15] Update
packages/samples/headless-ssr-commerce/app/layout.tsx
Co-authored-by: Frederic Beaudoin
---
packages/samples/headless-ssr-commerce/app/layout.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/samples/headless-ssr-commerce/app/layout.tsx b/packages/samples/headless-ssr-commerce/app/layout.tsx
index e1db209ed3c..b8d305f518c 100644
--- a/packages/samples/headless-ssr-commerce/app/layout.tsx
+++ b/packages/samples/headless-ssr-commerce/app/layout.tsx
@@ -2,7 +2,7 @@ import Link from 'next/link';
export const metadata = {
title: 'Headless SSR examples',
- description: 'Examples of using framework @coveo/headless-react/ssr-commerce',
+ description: 'Examples of using @coveo/headless-react/ssr-commerce',
};
export default function RootLayout({children}: {children: React.ReactNode}) {
From c67d27dba5e4a5fdb933adfa91497f43526fd61a Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Wed, 6 Nov 2024 15:14:30 -0500
Subject: [PATCH 09/15] Update
packages/samples/headless-ssr-commerce/package.json
Co-authored-by: Frederic Beaudoin
---
packages/samples/headless-ssr-commerce/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/samples/headless-ssr-commerce/package.json b/packages/samples/headless-ssr-commerce/package.json
index 2d2da69090e..e0f6f620249 100644
--- a/packages/samples/headless-ssr-commerce/package.json
+++ b/packages/samples/headless-ssr-commerce/package.json
@@ -1,6 +1,6 @@
{
"name": "@coveo/headless-ssr-commerce-samples",
- "description": "Examples of framework @coveo/headless-react/ssr-commerce utils using Next.js app router",
+ "description": "Examples of @coveo/headless-react/ssr-commerce utils using Next.js app router",
"version": "0.0.0",
"private": true,
"scripts": {
From 86d63ec6baaa0fa11a4fbdc011c908c9c91c8c07 Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Wed, 6 Nov 2024 15:17:30 -0500
Subject: [PATCH 10/15] apply review comments
https://coveord.atlassian.net/browse/KIT-3699
---
.../app/_components/pages/listing-page.tsx | 2 +-
.../app/_components/recommendation-list.tsx | 5 ++---
.../headless-ssr-commerce/app/_components/summary.tsx | 2 +-
packages/samples/headless-ssr-commerce/app/layout.tsx | 1 -
4 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/packages/samples/headless-ssr-commerce/app/_components/pages/listing-page.tsx b/packages/samples/headless-ssr-commerce/app/_components/pages/listing-page.tsx
index 4cfc2e95754..64fa887d9f0 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/pages/listing-page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/pages/listing-page.tsx
@@ -52,7 +52,7 @@ export default function ListingPage({
- {/* // TODO: FIXME: Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react/index").ReactNode'.
+ {/* // TODO: Add KIT-3701: Type 'React.ReactNode' is not assignable to type 'import(".../node_modules/@types/react/index").ReactNode'.
Type 'bigint' is not assignable to type 'ReactNode'.*/}
<>{children}>
diff --git a/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx b/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
index 5e71137880b..2f296b09dbc 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
@@ -2,10 +2,9 @@
import {Product} from '@coveo/headless-react/ssr-commerce';
import {useRouter} from 'next/navigation';
-import {FunctionComponent} from 'react';
import {usePopularBoughtRecs} from '../_lib/commerce-engine';
-export const Recommendations: FunctionComponent = () => {
+export default function Recommendations() {
// TODO: KIT-3503: refresh recs server side
const {state, controller} = usePopularBoughtRecs();
@@ -35,4 +34,4 @@ export const Recommendations: FunctionComponent = () => {
>
);
-};
+}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/summary.tsx b/packages/samples/headless-ssr-commerce/app/_components/summary.tsx
index 887f6d26182..49ac48ddc1d 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/summary.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/summary.tsx
@@ -20,7 +20,7 @@ export default function Summary() {
return null;
}
- // TODO: add query to summary state
+ // TODO: KIT-3719 - add query to summary state
// return (
//
// for {state.query}
diff --git a/packages/samples/headless-ssr-commerce/app/layout.tsx b/packages/samples/headless-ssr-commerce/app/layout.tsx
index b8d305f518c..630a915ef5a 100644
--- a/packages/samples/headless-ssr-commerce/app/layout.tsx
+++ b/packages/samples/headless-ssr-commerce/app/layout.tsx
@@ -13,7 +13,6 @@ export default function RootLayout({children}: {children: React.ReactNode}) {
Search Page
Listing Page
- Recommendations
{children}
From 2e2e460a38e4f32fe48d49ac70cfaaefb4d9bb3f Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Wed, 6 Nov 2024 15:40:50 -0500
Subject: [PATCH 11/15] update lock
https://coveord.atlassian.net/browse/KIT-3699
---
package-lock.json | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 74ac35f6a49..9eaf372c031 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -57735,8 +57735,7 @@
"devDependencies": {
"@coveo/release": "1.0.0",
"@testing-library/react": "14.3.1",
- "@types/react": "18.3.3",
- "@types/react-dom": "18.3.0",
+ "@types/jest": "29.5.12",
"@typescript-eslint/eslint-plugin": "7.17.0",
"eslint-plugin-react": "7.35.0",
"eslint-plugin-testing-library": "6.2.2",
@@ -65102,7 +65101,7 @@
"name": "@coveo/headless-ssr-commerce-samples",
"version": "0.0.0",
"dependencies": {
- "@coveo/headless": "3.8.0",
+ "@coveo/headless-react": "2.0.8",
"next": "14.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
From 4ae0e6c0c8b54e8a94b6e9d859c4a6355570c8a3 Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Thu, 7 Nov 2024 11:27:04 -0500
Subject: [PATCH 12/15] update package lock
https://coveord.atlassian.net/browse/KIT-3699
---
package-lock.json | 102 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 98 insertions(+), 4 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index ee81943094d..010c7f1b6da 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6229,7 +6229,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
- "dev": true,
"engines": {
"node": ">=14"
}
@@ -22151,8 +22150,7 @@
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
- "deprecated": "Use your platform's native atob() and btoa() methods instead",
- "dev": true
+ "deprecated": "Use your platform's native atob() and btoa() methods instead"
},
"node_modules/abbrev": {
"version": "2.0.0",
@@ -25923,6 +25921,37 @@
"typescript": ">=4"
}
},
+ "node_modules/coveo.analytics": {
+ "version": "2.30.38",
+ "resolved": "https://registry.npmjs.org/coveo.analytics/-/coveo.analytics-2.30.38.tgz",
+ "integrity": "sha512-CxiBWV7XxDNAyCWS7gwikHjJYz8NigYVHSkGU23JkcQf2oK0XJEsxcU/eRN3VRBfLLmhBTRZbpWJ1SW2imDovQ==",
+ "dependencies": {
+ "@types/uuid": "^9.0.0",
+ "cross-fetch": "^3.1.5",
+ "react-native-get-random-values": "^1.11.0",
+ "uuid": "^9.0.0"
+ }
+ },
+ "node_modules/coveo.analytics/node_modules/cross-fetch": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
+ "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
+ "dependencies": {
+ "node-fetch": "^2.6.12"
+ }
+ },
+ "node_modules/coveo.analytics/node_modules/uuid": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+ "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/create-jest": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
@@ -51612,7 +51641,6 @@
"version": "5.28.4",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
"integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==",
- "dev": true,
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
@@ -65115,6 +65143,72 @@
"typescript": "5.4.5"
}
},
+ "packages/samples/headless-ssr-commerce/node_modules/@coveo/bueno": {
+ "version": "0.46.3",
+ "resolved": "https://registry.npmjs.org/@coveo/bueno/-/bueno-0.46.3.tgz",
+ "integrity": "sha512-xIxv7CqJfFQjJsY6KkMnVqjNsbRz8ezeiWS+d4CFqH9RCqJNV0ct9gklMvf8WoxOLXAICBpzMy3BaaDVjyp2pA=="
+ },
+ "packages/samples/headless-ssr-commerce/node_modules/@coveo/headless": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/@coveo/headless/-/headless-3.4.1.tgz",
+ "integrity": "sha512-QdZq00ek4RfHYU1ZfX8geO4pD654hN1Fu2uiFCi3IZdBlAnwryIpWYW4YndSx3DilC+TV5dcvIhK5jPYZyN2UA==",
+ "dependencies": {
+ "@coveo/bueno": "0.46.3",
+ "@coveo/relay": "0.7.10",
+ "@coveo/relay-event-types": "9.4.0",
+ "@microsoft/fetch-event-source": "2.0.1",
+ "@reduxjs/toolkit": "2.2.7",
+ "abab": "2.0.6",
+ "abortcontroller-polyfill": "1.7.5",
+ "coveo.analytics": "2.30.38",
+ "dayjs": "1.11.12",
+ "exponential-backoff": "3.1.0",
+ "fast-equals": "5.0.1",
+ "navigator.sendbeacon": "0.0.20",
+ "node-abort-controller": "^3.0.0",
+ "pino": "8.21.0",
+ "redux-thunk": "3.1.0",
+ "ts-debounce": "4.0.0",
+ "undici": "5.28.4"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.13",
+ "pino-pretty": "^6.0.0 || ^10.0.0 || ^11.0.0"
+ }
+ },
+ "packages/samples/headless-ssr-commerce/node_modules/@coveo/headless-react": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/@coveo/headless-react/-/headless-react-2.0.8.tgz",
+ "integrity": "sha512-UYFfN4CIfBIvpyDScKoAvAlqPWs9Rte57staR4K15wGTvIZnRQAhw0B/UYf/muFi+RfjtW8OlrwbeQraOedQ5Q==",
+ "dependencies": {
+ "@coveo/headless": "3.4.1"
+ },
+ "engines": {
+ "node": "^18 || ^20"
+ },
+ "peerDependencies": {
+ "react": "^18",
+ "react-dom": "^18"
+ }
+ },
+ "packages/samples/headless-ssr-commerce/node_modules/@coveo/relay-event-types": {
+ "version": "9.4.0",
+ "resolved": "https://registry.npmjs.org/@coveo/relay-event-types/-/relay-event-types-9.4.0.tgz",
+ "integrity": "sha512-Fsm3fUWj5ofbYB0Bz4j97LXwsX6MRxYA7NX4DOF7BrXW6GlSvJCH5lR7EModMsi9OTy9ee6pQ2A2xvXkWMBmGg=="
+ },
+ "packages/samples/headless-ssr-commerce/node_modules/dayjs": {
+ "version": "1.11.12",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz",
+ "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg=="
+ },
+ "packages/samples/headless-ssr-commerce/node_modules/exponential-backoff": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.0.tgz",
+ "integrity": "sha512-oBuz5SYz5zzyuHINoe9ooePwSu0xApKWgeNzok4hZ5YKXFh9zrQBEM15CXqoZkJJPuI2ArvqjPQd8UKJA753XA=="
+ },
"packages/samples/headless-ssr/app-router": {
"name": "@coveo/headless-ssr-samples-app-router",
"version": "0.0.0",
From bb985356f250e148c6da7c07e897cfe7b72f8157 Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Fri, 8 Nov 2024 10:06:33 -0500
Subject: [PATCH 13/15] fix lock
https://coveord.atlassian.net/browse/KIT-3699
---
package-lock.json | 108 ++----------------
packages/headless-react/package.json | 4 +-
.../headless-ssr-commerce/package.json | 2 +-
3 files changed, 10 insertions(+), 104 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 010c7f1b6da..3c359afa082 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6229,6 +6229,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
+ "dev": true,
"engines": {
"node": ">=14"
}
@@ -22150,7 +22151,8 @@
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
- "deprecated": "Use your platform's native atob() and btoa() methods instead"
+ "deprecated": "Use your platform's native atob() and btoa() methods instead",
+ "dev": true
},
"node_modules/abbrev": {
"version": "2.0.0",
@@ -25921,37 +25923,6 @@
"typescript": ">=4"
}
},
- "node_modules/coveo.analytics": {
- "version": "2.30.38",
- "resolved": "https://registry.npmjs.org/coveo.analytics/-/coveo.analytics-2.30.38.tgz",
- "integrity": "sha512-CxiBWV7XxDNAyCWS7gwikHjJYz8NigYVHSkGU23JkcQf2oK0XJEsxcU/eRN3VRBfLLmhBTRZbpWJ1SW2imDovQ==",
- "dependencies": {
- "@types/uuid": "^9.0.0",
- "cross-fetch": "^3.1.5",
- "react-native-get-random-values": "^1.11.0",
- "uuid": "^9.0.0"
- }
- },
- "node_modules/coveo.analytics/node_modules/cross-fetch": {
- "version": "3.1.8",
- "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
- "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
- "dependencies": {
- "node-fetch": "^2.6.12"
- }
- },
- "node_modules/coveo.analytics/node_modules/uuid": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
- "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
- "funding": [
- "https://github.com/sponsors/broofa",
- "https://github.com/sponsors/ctavan"
- ],
- "bin": {
- "uuid": "dist/bin/uuid"
- }
- },
"node_modules/create-jest": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
@@ -51641,6 +51612,7 @@
"version": "5.28.4",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
"integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==",
+ "dev": true,
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
@@ -57777,8 +57749,8 @@
"node": "^20.9.0 || ^22.11.0"
},
"optionalDependencies": {
- "@types/react": "^18.0.0",
- "@types/react-dom": "^18.0.0"
+ "@types/react": "18.3.3",
+ "@types/react-dom": "18.3.0"
},
"peerDependencies": {
"@types/react": "18.3.3",
@@ -65129,7 +65101,7 @@
"name": "@coveo/headless-ssr-commerce-samples",
"version": "0.0.0",
"dependencies": {
- "@coveo/headless-react": "2.0.8",
+ "@coveo/headless-react": "2.1.0",
"next": "14.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
@@ -65143,72 +65115,6 @@
"typescript": "5.4.5"
}
},
- "packages/samples/headless-ssr-commerce/node_modules/@coveo/bueno": {
- "version": "0.46.3",
- "resolved": "https://registry.npmjs.org/@coveo/bueno/-/bueno-0.46.3.tgz",
- "integrity": "sha512-xIxv7CqJfFQjJsY6KkMnVqjNsbRz8ezeiWS+d4CFqH9RCqJNV0ct9gklMvf8WoxOLXAICBpzMy3BaaDVjyp2pA=="
- },
- "packages/samples/headless-ssr-commerce/node_modules/@coveo/headless": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/@coveo/headless/-/headless-3.4.1.tgz",
- "integrity": "sha512-QdZq00ek4RfHYU1ZfX8geO4pD654hN1Fu2uiFCi3IZdBlAnwryIpWYW4YndSx3DilC+TV5dcvIhK5jPYZyN2UA==",
- "dependencies": {
- "@coveo/bueno": "0.46.3",
- "@coveo/relay": "0.7.10",
- "@coveo/relay-event-types": "9.4.0",
- "@microsoft/fetch-event-source": "2.0.1",
- "@reduxjs/toolkit": "2.2.7",
- "abab": "2.0.6",
- "abortcontroller-polyfill": "1.7.5",
- "coveo.analytics": "2.30.38",
- "dayjs": "1.11.12",
- "exponential-backoff": "3.1.0",
- "fast-equals": "5.0.1",
- "navigator.sendbeacon": "0.0.20",
- "node-abort-controller": "^3.0.0",
- "pino": "8.21.0",
- "redux-thunk": "3.1.0",
- "ts-debounce": "4.0.0",
- "undici": "5.28.4"
- },
- "engines": {
- "node": ">=12"
- },
- "peerDependencies": {
- "encoding": "^0.1.13",
- "pino-pretty": "^6.0.0 || ^10.0.0 || ^11.0.0"
- }
- },
- "packages/samples/headless-ssr-commerce/node_modules/@coveo/headless-react": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/@coveo/headless-react/-/headless-react-2.0.8.tgz",
- "integrity": "sha512-UYFfN4CIfBIvpyDScKoAvAlqPWs9Rte57staR4K15wGTvIZnRQAhw0B/UYf/muFi+RfjtW8OlrwbeQraOedQ5Q==",
- "dependencies": {
- "@coveo/headless": "3.4.1"
- },
- "engines": {
- "node": "^18 || ^20"
- },
- "peerDependencies": {
- "react": "^18",
- "react-dom": "^18"
- }
- },
- "packages/samples/headless-ssr-commerce/node_modules/@coveo/relay-event-types": {
- "version": "9.4.0",
- "resolved": "https://registry.npmjs.org/@coveo/relay-event-types/-/relay-event-types-9.4.0.tgz",
- "integrity": "sha512-Fsm3fUWj5ofbYB0Bz4j97LXwsX6MRxYA7NX4DOF7BrXW6GlSvJCH5lR7EModMsi9OTy9ee6pQ2A2xvXkWMBmGg=="
- },
- "packages/samples/headless-ssr-commerce/node_modules/dayjs": {
- "version": "1.11.12",
- "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz",
- "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg=="
- },
- "packages/samples/headless-ssr-commerce/node_modules/exponential-backoff": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.0.tgz",
- "integrity": "sha512-oBuz5SYz5zzyuHINoe9ooePwSu0xApKWgeNzok4hZ5YKXFh9zrQBEM15CXqoZkJJPuI2ArvqjPQd8UKJA753XA=="
- },
"packages/samples/headless-ssr/app-router": {
"name": "@coveo/headless-ssr-samples-app-router",
"version": "0.0.0",
diff --git a/packages/headless-react/package.json b/packages/headless-react/package.json
index fabae293dcc..e3536ae8a5e 100644
--- a/packages/headless-react/package.json
+++ b/packages/headless-react/package.json
@@ -56,8 +56,8 @@
"@types/react-dom": "18.3.0"
},
"optionalDependencies": {
- "@types/react": "^18.0.0",
- "@types/react-dom": "^18.0.0"
+ "@types/react": "18.3.3",
+ "@types/react-dom": "18.3.0"
},
"engines": {
"node": "^20.9.0 || ^22.11.0"
diff --git a/packages/samples/headless-ssr-commerce/package.json b/packages/samples/headless-ssr-commerce/package.json
index e0f6f620249..9489073b47d 100644
--- a/packages/samples/headless-ssr-commerce/package.json
+++ b/packages/samples/headless-ssr-commerce/package.json
@@ -11,7 +11,7 @@
"build:next": "next build"
},
"dependencies": {
- "@coveo/headless-react": "2.0.8",
+ "@coveo/headless-react": "2.1.0",
"next": "14.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
From 90c387ee64634202752f885a4e1e47e09b9cef8b Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Fri, 8 Nov 2024 10:17:38 -0500
Subject: [PATCH 14/15] typo
https://coveord.atlassian.net/browse/KIT-3699
---
.../app/_components/breadcrumb-manager.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/samples/headless-ssr-commerce/app/_components/breadcrumb-manager.tsx b/packages/samples/headless-ssr-commerce/app/_components/breadcrumb-manager.tsx
index 844b9dc3f22..45e612801c6 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/breadcrumb-manager.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/breadcrumb-manager.tsx
@@ -10,7 +10,7 @@ import {
import {useBreadcrumbManager} from '../_lib/commerce-engine';
export default function BreadcrumbManager() {
- const {state, controller} = useBreadcrumbManager();
+ const {state, methods} = useBreadcrumbManager();
const renderBreadcrumbValue = (
value:
@@ -47,7 +47,7 @@ export default function BreadcrumbManager() {
return (
- Clear all filters
+ Clear all filters
{state.facetBreadcrumbs.map((facetBreadcrumb) => {
From b8a51e9e26aed081d5e69525cffbf7524f66342c Mon Sep 17 00:00:00 2001
From: ylakhdar
Date: Fri, 8 Nov 2024 10:44:05 -0500
Subject: [PATCH 15/15] fix imports
https://coveord.atlassian.net/browse/KIT-3699
---
.../app/_components/cart.tsx | 8 ++++----
.../app/_components/facets/facet-generator.tsx | 13 +++++--------
.../app/_components/instant-product.tsx | 4 ++--
.../app/_components/pages/product-page.tsx | 2 +-
.../app/_components/pagination.tsx | 8 ++++----
.../app/_components/product-list.tsx | 9 +++------
.../app/_components/recent-queries.tsx | 6 +++---
.../app/_components/recommendation-list.tsx | 9 +++------
.../app/_components/search-box.tsx | 12 ++++++------
.../app/_components/show-more.tsx | 6 +++---
.../app/_components/sort.tsx | 8 ++++----
.../app/_components/standalone-search-box.tsx | 16 ++++++++--------
.../headless-ssr-commerce/app/listing/page.tsx | 2 +-
.../headless-ssr-commerce/app/search/page.tsx | 2 +-
14 files changed, 48 insertions(+), 57 deletions(-)
diff --git a/packages/samples/headless-ssr-commerce/app/_components/cart.tsx b/packages/samples/headless-ssr-commerce/app/_components/cart.tsx
index 55274cb7b38..d163f6b2af7 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/cart.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/cart.tsx
@@ -5,11 +5,11 @@ import {useCart, useContext} from '../_lib/commerce-engine';
import {formatCurrency} from '../_utils/format-currency';
export default function Cart() {
- const {state, controller} = useCart();
+ const {state, methods} = useCart();
const {state: contextState} = useContext();
const adjustQuantity = (item: CartItem, delta: number) => {
- controller?.updateItemQuantity({
+ methods?.updateItemQuantity({
...item,
quantity: item.quantity + delta,
});
@@ -20,11 +20,11 @@ export default function Cart() {
};
const purchase = () => {
- controller?.purchase({id: crypto.randomUUID(), revenue: state.totalPrice});
+ methods?.purchase({id: crypto.randomUUID(), revenue: state.totalPrice});
};
const emptyCart = () => {
- controller?.empty();
+ methods?.empty();
};
const language = () => contextState.language;
diff --git a/packages/samples/headless-ssr-commerce/app/_components/facets/facet-generator.tsx b/packages/samples/headless-ssr-commerce/app/_components/facets/facet-generator.tsx
index 0d6dcbb26bf..b10fe969106 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/facets/facet-generator.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/facets/facet-generator.tsx
@@ -7,7 +7,7 @@ import NumericFacet from './numeric-facet';
import RegularFacet from './regular-facet';
export default function FacetGenerator() {
- const {state, controller} = useFacetGenerator();
+ const {state, methods} = useFacetGenerator();
return (
@@ -18,7 +18,7 @@ export default function FacetGenerator() {
return (
);
@@ -28,7 +28,7 @@ export default function FacetGenerator() {
return (
);
@@ -50,7 +47,7 @@ export default function FacetGenerator() {
return (
{
- controller?.interactiveProduct({options: {product}}).select();
+ methods?.interactiveProduct({options: {product}}).select();
router.push(
`/products/${product.ec_product_id}?name=${product.ec_name}&price=${product.ec_price}`
);
diff --git a/packages/samples/headless-ssr-commerce/app/_components/pages/product-page.tsx b/packages/samples/headless-ssr-commerce/app/_components/pages/product-page.tsx
index 0cb4ea535c0..0967d7b249a 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/pages/product-page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/pages/product-page.tsx
@@ -8,7 +8,7 @@ import {
import {NavigatorContext} from '@coveo/headless-react/ssr-commerce';
import {useSearchParams} from 'next/navigation';
import {useEffect, useState} from 'react';
-import {Recommendations} from '../recommendation-list';
+import Recommendations from '../recommendation-list';
interface IProductPageProps {
staticState: StandaloneStaticState;
diff --git a/packages/samples/headless-ssr-commerce/app/_components/pagination.tsx b/packages/samples/headless-ssr-commerce/app/_components/pagination.tsx
index b8acfd7bb27..79e3075a2ed 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/pagination.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/pagination.tsx
@@ -3,7 +3,7 @@
import {usePagination} from '../_lib/commerce-engine';
export default function Pagination() {
- const {state, controller} = usePagination();
+ const {state, methods} = usePagination();
const renderPageRadioButtons = () => {
return Array.from({length: state.totalPages}, (_, i) => {
@@ -15,7 +15,7 @@ export default function Pagination() {
name="page"
value={page - 1}
checked={state.page === page - 1}
- onChange={() => controller?.selectPage(page - 1)}
+ onChange={() => methods?.selectPage(page - 1)}
/>
{page}
@@ -31,7 +31,7 @@ export default function Pagination() {
{'<'}
@@ -39,7 +39,7 @@ export default function Pagination() {
{'>'}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/product-list.tsx b/packages/samples/headless-ssr-commerce/app/_components/product-list.tsx
index 8c5b9a6701e..6d62896ad9a 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/product-list.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/product-list.tsx
@@ -5,12 +5,12 @@ import {useRouter} from 'next/navigation';
import {useProductList} from '../_lib/commerce-engine';
export default function ProductList() {
- const {state, controller} = useProductList();
+ const {state, methods} = useProductList();
const router = useRouter();
const onProductClick = (product: Product) => {
- controller?.interactiveProduct({options: {product}}).select();
+ methods?.interactiveProduct({options: {product}}).select();
router.push(
`/products/${product.ec_product_id}?name=${product.ec_name}&price=${product.ec_price}`
);
@@ -20,10 +20,7 @@ export default function ProductList() {
{state.products.map((product) => (
- onProductClick(product)}
- >
+ onProductClick(product)}>
{product.ec_name}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/recent-queries.tsx b/packages/samples/headless-ssr-commerce/app/_components/recent-queries.tsx
index 323b4cfb62e..9055d0ca43d 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/recent-queries.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/recent-queries.tsx
@@ -4,8 +4,8 @@ import {
} from '../_lib/commerce-engine';
export default function RecentQueries() {
- const {state, controller} = useRecentQueriesList();
- const {controller: instantProductsController} = useInstantProducts();
+ const {state, methods} = useRecentQueriesList();
+ const {methods: instantProductsController} = useInstantProducts();
return (
@@ -16,7 +16,7 @@ export default function RecentQueries() {
{query}
instantProductsController?.updateQuery(query)}
- onClick={() => controller?.executeRecentQuery(index)}
+ onClick={() => methods?.executeRecentQuery(index)}
dangerouslySetInnerHTML={{__html: query}}
>
diff --git a/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx b/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
index 2f296b09dbc..42171cb944c 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/recommendation-list.tsx
@@ -6,12 +6,12 @@ import {usePopularBoughtRecs} from '../_lib/commerce-engine';
export default function Recommendations() {
// TODO: KIT-3503: refresh recs server side
- const {state, controller} = usePopularBoughtRecs();
+ const {state, methods} = usePopularBoughtRecs();
const router = useRouter();
const onProductClick = (product: Product) => {
- controller?.interactiveProduct({options: {product}}).select();
+ methods?.interactiveProduct({options: {product}}).select();
router.push(
`/products/${product.ec_product_id}?name=${product.ec_name}&price=${product.ec_price}`
);
@@ -23,10 +23,7 @@ export default function Recommendations() {
{state.headline}
{state.products.map((product) => (
- onProductClick(product)}
- >
+ onProductClick(product)}>
{product.ec_name}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/search-box.tsx b/packages/samples/headless-ssr-commerce/app/_components/search-box.tsx
index 8926119fc4b..a3aa4f4b7b7 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/search-box.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/search-box.tsx
@@ -10,9 +10,9 @@ import InstantProducts from './instant-product';
import RecentQueries from './recent-queries';
export default function SearchBox() {
- const {state, controller} = useSearchBox();
+ const {state, methods} = useSearchBox();
const {state: recentQueriesState} = useRecentQueriesList();
- const {state: instantProductsState, controller: instantProductsController} =
+ const {state: instantProductsState, methods: instantProductsController} =
useInstantProducts();
const [isInputFocused, setIsInputFocused] = useState(false);
@@ -20,7 +20,7 @@ export default function SearchBox() {
const onSearchBoxInputChange = (e: React.ChangeEvent) => {
setIsSelectingSuggestion(true);
- controller?.updateText(e.target.value);
+ methods?.updateText(e.target.value);
instantProductsController?.updateQuery(e.target.value);
};
@@ -44,10 +44,10 @@ export default function SearchBox() {
>
{state.value !== '' && (
- X
+ X
)}
- Search
+ Search
{isInputFocused && (
<>
@@ -64,7 +64,7 @@ export default function SearchBox() {
)
}
onClick={() =>
- controller?.selectSuggestion(suggestion.rawValue)
+ methods?.selectSuggestion(suggestion.rawValue)
}
dangerouslySetInnerHTML={{
__html: suggestion.highlightedValue,
diff --git a/packages/samples/headless-ssr-commerce/app/_components/show-more.tsx b/packages/samples/headless-ssr-commerce/app/_components/show-more.tsx
index e3bb103b18f..050faf97ac0 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/show-more.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/show-more.tsx
@@ -3,16 +3,16 @@
import {usePagination, useSummary} from '../_lib/commerce-engine';
export default function ShowMore() {
- const {state, controller} = usePagination();
+ const {state, methods} = usePagination();
const {state: summaryState} = useSummary();
const handleFetchMore = () => {
- controller?.fetchMoreProducts();
+ methods?.fetchMoreProducts();
};
const isDisabled = () => {
return (
- !controller ||
+ !methods ||
summaryState?.lastProduct === summaryState?.totalNumberOfProducts
);
};
diff --git a/packages/samples/headless-ssr-commerce/app/_components/sort.tsx b/packages/samples/headless-ssr-commerce/app/_components/sort.tsx
index e6db096652f..4983d4227dd 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/sort.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/sort.tsx
@@ -4,7 +4,7 @@
import {useSort} from '../_lib/commerce-engine';
export default function Sort() {
- const {state, controller} = useSort();
+ const {state, methods} = useSort();
if (state.availableSorts.length === 0) {
return null;
@@ -27,14 +27,14 @@ export default function Sort() {
name="sorts"
id="sorts-select"
value={JSON.stringify(state.appliedSort)}
- onChange={(e) => controller?.sortBy(JSON.parse(e.target.value))}
- disabled={!controller}
+ onChange={(e) => methods?.sortBy(JSON.parse(e.target.value))}
+ disabled={!methods}
>
{state.availableSorts.map((sort, index) => (
controller?.sortBy(sort)}
+ onSelect={() => methods?.sortBy(sort)}
>
{/* TODO:KIT-3700: there is a type mismatch with the sort criterion FIXME:!!*/}
{/* {getSortLabel(sort)} */}
diff --git a/packages/samples/headless-ssr-commerce/app/_components/standalone-search-box.tsx b/packages/samples/headless-ssr-commerce/app/_components/standalone-search-box.tsx
index 5e7b1d61f9a..44ae15eb74b 100644
--- a/packages/samples/headless-ssr-commerce/app/_components/standalone-search-box.tsx
+++ b/packages/samples/headless-ssr-commerce/app/_components/standalone-search-box.tsx
@@ -11,9 +11,9 @@ import InstantProducts from './instant-product';
import RecentQueries from './recent-queries';
export default function StandaloneSearchBox() {
- const {state, controller} = useStandaloneSearchBox();
+ const {state, methods} = useStandaloneSearchBox();
const {state: recentQueriesState} = useRecentQueriesList();
- const {state: instantProductsState, controller: instantProductsController} =
+ const {state: instantProductsState, methods: instantProductsController} =
useInstantProducts();
const [isInputFocused, setIsInputFocused] = useState(false);
@@ -25,13 +25,13 @@ export default function StandaloneSearchBox() {
if (state.redirectTo === '/search') {
const url = `${state.redirectTo}#q=${encodeURIComponent(state.value)}`;
router.push(url, {scroll: false});
- controller?.afterRedirection();
+ methods?.afterRedirection();
}
- }, [state.redirectTo, state.value, router, controller]);
+ }, [state.redirectTo, state.value, router, methods]);
const onSearchBoxInputChange = (e: React.ChangeEvent) => {
setIsSelectingSuggestion(true);
- controller?.updateText(e.target.value);
+ methods?.updateText(e.target.value);
instantProductsController?.updateQuery(e.target.value);
};
@@ -55,10 +55,10 @@ export default function StandaloneSearchBox() {
>
{state.value !== '' && (
- X
+ X
)}
- controller?.submit()}>Search
+ methods?.submit()}>Search
{isInputFocused && (
<>
@@ -75,7 +75,7 @@ export default function StandaloneSearchBox() {
)
}
onClick={() =>
- controller?.selectSuggestion(suggestion.rawValue)
+ methods?.selectSuggestion(suggestion.rawValue)
}
dangerouslySetInnerHTML={{
__html: suggestion.highlightedValue,
diff --git a/packages/samples/headless-ssr-commerce/app/listing/page.tsx b/packages/samples/headless-ssr-commerce/app/listing/page.tsx
index e03abd76d59..99376b8407a 100644
--- a/packages/samples/headless-ssr-commerce/app/listing/page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/listing/page.tsx
@@ -5,7 +5,7 @@ import FacetGenerator from '../_components/facets/facet-generator';
import ListingPage from '../_components/pages/listing-page';
import Pagination from '../_components/pagination';
import ProductList from '../_components/product-list';
-import {Recommendations} from '../_components/recommendation-list';
+import Recommendations from '../_components/recommendation-list';
import Sort from '../_components/sort';
import StandaloneSearchBox from '../_components/standalone-search-box';
import Summary from '../_components/summary';
diff --git a/packages/samples/headless-ssr-commerce/app/search/page.tsx b/packages/samples/headless-ssr-commerce/app/search/page.tsx
index 529e980932d..8ec25f92e8f 100644
--- a/packages/samples/headless-ssr-commerce/app/search/page.tsx
+++ b/packages/samples/headless-ssr-commerce/app/search/page.tsx
@@ -3,7 +3,7 @@ import BreadcrumbManager from '../_components/breadcrumb-manager';
import FacetGenerator from '../_components/facets/facet-generator';
import SearchPage from '../_components/pages/search-page';
import ProductList from '../_components/product-list';
-import {Recommendations} from '../_components/recommendation-list';
+import Recommendations from '../_components/recommendation-list';
import SearchBox from '../_components/search-box';
import ShowMore from '../_components/show-more';
import Summary from '../_components/summary';