Skip to content

Commit

Permalink
feat(headless): add support for breadcrumb manager in commerce ssr (#…
Browse files Browse the repository at this point in the history
…4601)

https://coveord.atlassian.net/browse/KIT-3464

This PR adds the breadcrumb manager definer function and a sample for
it.
  • Loading branch information
alexprudhomme authored Oct 30, 2024
1 parent 0c526de commit 851257f
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {ensureAtLeastOneSolutionType} from '../../../../app/commerce-ssr-engine/common.js';
import {
ControllerDefinitionOption,
SolutionType,
SubControllerDefinitionWithoutProps,
} from '../../../../app/commerce-ssr-engine/types/common.js';
import {buildProductListing} from '../../product-listing/headless-product-listing.js';
import {buildSearch} from '../../search/headless-search.js';
import {
BreadcrumbManager,
BreadcrumbManagerState,
} from './headless-core-breadcrumb-manager.js';

export type {BreadcrumbManager, BreadcrumbManagerState};

/**
* Defines a `BreadcrumbManager` controller instance.
*
* @returns The `BreadcrumbManager` controller definition.
*
* @internal
*/
export function defineBreadcrumbManager<
TOptions extends ControllerDefinitionOption | undefined,
>(options?: TOptions) {
ensureAtLeastOneSolutionType(options);
return {
...options,
build: (engine, solutionType) =>
solutionType === SolutionType.listing
? buildProductListing(engine).breadcrumbManager()
: buildSearch(engine).breadcrumbManager(),
} as SubControllerDefinitionWithoutProps<BreadcrumbManager, TOptions>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
buildCoreCommerceFacet,
} from '../headless-core-commerce-facet.js';

export type {DateFacetValue};

export type DateFacetOptions = Omit<
CoreCommerceFacetOptions,
'toggleSelectActionCreator' | 'toggleExcludeActionCreator'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
import {
DateFacet,
DateFacetState,
DateFacetValue,
getDateFacetState,
} from '../date/headless-commerce-date-facet.js';
import {
Expand All @@ -53,6 +54,7 @@ import {
import {
getNumericFacetState,
NumericFacet,
NumericFacetValue,
NumericFacetState,
} from '../numeric/headless-commerce-numeric-facet.js';
import {
Expand All @@ -72,8 +74,10 @@ export type {
CategoryFacetValue,
CategoryFacetSearchResult,
DateFacet,
DateFacetValue,
DateFacetState,
NumericFacet,
NumericFacetValue,
NumericFacetState,
RegularFacet,
RegularFacetState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
buildCoreCommerceFacet,
} from '../headless-core-commerce-facet.js';

export type {NumericFacetValue};

export type NumericFacetOptions = Omit<
CoreCommerceFacetOptions,
'toggleSelectActionCreator' | 'toggleExcludeActionCreator'
Expand Down
8 changes: 8 additions & 0 deletions packages/headless/src/ssr-commerce.index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ export type {
CategoryFacetValue,
CategoryFacetSearchResult,
DateFacet,
DateFacetValue,
DateFacetState,
FacetGenerator,
FacetGeneratorState,
NumericFacet,
NumericFacetValue,
NumericFacetState,
RegularFacet,
RegularFacetState,
Expand Down Expand Up @@ -149,6 +151,12 @@ export type {
} from './controllers/commerce/core/sort/headless-core-commerce-sort.ssr.js';
export {defineSort} from './controllers/commerce/core/sort/headless-core-commerce-sort.ssr.js';

export type {
BreadcrumbManager,
BreadcrumbManagerState,
} from './controllers/commerce/core/breadcrumb-manager/headless-core-breadcrumb-manager.ssr.js';
export {defineBreadcrumbManager} from './controllers/commerce/core/breadcrumb-manager/headless-core-breadcrumb-manager.ssr.js';

export type {
Summary,
ProductListingSummaryState,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
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);

useEffect(() => {
controller?.subscribe(() => setState(controller.state));
}, [controller]);

const renderBreadcrumbValue = (
value:
| CategoryFacetValue
| RegularFacetValue
| NumericFacetValue
| DateFacetValue,
type: string
) => {
switch (type) {
case 'hierarchical':
return (value as CategoryFacetValue).path.join(' > ');
case 'regular':
return (value as RegularFacetValue).value;
case 'numericalRange':
return (
(value as NumericFacetValue).start +
' - ' +
(value as NumericFacetValue).end
);
case 'dateRange':
return (
(value as DateFacetValue).start +
' - ' +
(value as DateFacetValue).end
);
default:
return null;
}
};

return (
<div>
<div>
<button onClick={controller?.deselectAll}>Clear all filters</button>
</div>
<ul>
{state.facetBreadcrumbs.map((facetBreadcrumb) => {
return (
<li key={`${facetBreadcrumb.facetId}-breadcrumbs`}>
{facetBreadcrumb.values.map((value, index) => {
return (
<button
key={`${value.value}-breadcrumb-${index}`}
onClick={() => value.deselect()}
>
{facetBreadcrumb.facetDisplayName}:{' '}
{renderBreadcrumbValue(value.value, facetBreadcrumb.type)} X
</button>
);
})}
</li>
);
})}
</ul>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
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';
Expand Down Expand Up @@ -63,6 +64,10 @@ export default function ListingPage({
hydratedState?.controllers.instantProducts
}
/>
<BreadcrumbManager
staticState={staticState.controllers.breadcrumbManager.state}
controller={hydratedState?.controllers.breadcrumbManager}
/>
<FacetGenerator
staticState={staticState.controllers.facetGenerator.state}
controller={hydratedState?.controllers.facetGenerator}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
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';
Expand Down Expand Up @@ -75,6 +76,10 @@ export default function SearchPage({
hydratedState?.controllers.instantProducts
}
/>
<BreadcrumbManager
staticState={staticState.controllers.breadcrumbManager.state}
controller={hydratedState?.controllers.breadcrumbManager}
/>
<FacetGenerator
staticState={staticState.controllers.facetGenerator.state}
controller={hydratedState?.controllers.facetGenerator}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
getSampleCommerceEngineConfiguration,
defineDidYouMean,
defineRecommendations, //defineParameterManager,
defineBreadcrumbManager,
} from '@coveo/headless/ssr-commerce';

type CommerceEngineConfig = CommerceEngineDefinitionOptions<
Expand Down Expand Up @@ -69,5 +70,6 @@ export default {
didYouMean: defineDidYouMean(), // TODO KIT-3463: implement did you mean in sample
//parameterManager: defineParameterManager(), // TODO KIT-3462: implement parameter manager in sample
facetGenerator: defineFacetGenerator(),
breadcrumbManager: defineBreadcrumbManager(),
},
} satisfies CommerceEngineConfig;

0 comments on commit 851257f

Please sign in to comment.