Skip to content

Commit 018ec4f

Browse files
authored
feat: add catalog search support (#455)
* feat: wip multi search * feat: add generated multi search * feat: search example excluded * feat: search example * feat: wip adapter * feat: wip adapter * feat: first pass working * feat: adding basic example without instant search * feat: working instant search example * feat: styling * feat: latest spec updates * feat: latest working example * fix: type * chore: update readme * feat: wip tests * feat: update to use new auth mechanism * feat: generate from latest search spec * feat: working with autocomplete * feat: use highlight snippet * feat(test): add basic tests * feat: updated path to use catalog directly * fix: hyphen * feat(test): search req test copied and refactored * feat(test): add placeholder for response mapping * feat: actual endpoint * feat: instant search updates * chore: changeset * feat: updated spa-search to use correct interface
1 parent 1127cec commit 018ec4f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+13783
-6
lines changed

.changeset/config.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
"spa-elastic-path-payments",
2626
"shopper-accounts-authentication",
2727
"next-account-checkout",
28-
"payments-paypal-express"
28+
"spa-search-instantsearch",
29+
"payments-paypal-express",
30+
"spa-search"
2931
]
3032
}

.changeset/good-crabs-happen.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@elasticpath/catalog-search-instantsearch-adapter": patch
3+
"@epcc-sdk/sdks-shopper": patch
4+
---
5+
6+
- Shopper SDK support for catalog search
7+
- Instant search support for catalog search
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Elastic Path Catalog Search with InstantSearch.js Example
2+
3+
This example demonstrates how to integrate Elastic Path's catalog search functionality with Algolia's InstantSearch.js library using the Elastic Path InstantSearch adapter. It showcases building a powerful search experience with faceted navigation, autocomplete, and real-time search results.
4+
5+
## Overview
6+
7+
This React SPA (Vite-based) example demonstrates:
8+
9+
- Integration of Elastic Path Catalog Search with InstantSearch.js components
10+
- Faceted search with hierarchical categories, brand filtering, and price ranges
11+
- Autocomplete functionality with search suggestions and recent searches
12+
- Real-time search results with pagination
13+
- Responsive search UI using InstantSearch components
14+
- Using the `@elasticpath/catalog-search-instantsearch-adapter` to connect Elastic Path's search API to InstantSearch
15+
16+
## Key Features
17+
18+
### Search Components
19+
20+
The example implements several InstantSearch components:
21+
22+
- **Autocomplete**: Search box with query suggestions and recent searches
23+
- **Hierarchical Menu**: Category navigation with nested categories
24+
- **Refinement Lists**: Brand filtering with facet counts
25+
- **Range Slider**: Price filtering with custom slider component
26+
- **Hits**: Product search results with custom hit component
27+
- **Pagination**: Navigate through search results
28+
- **Breadcrumb**: Shows current category path
29+
30+
### Elastic Path InstantSearch Adapter
31+
32+
The adapter (`@elasticpath/catalog-search-instantsearch-adapter`) bridges Elastic Path's search API with InstantSearch's expected format:
33+
34+
```typescript
35+
const catalogSearchInstantSearchAdapter = new CatalogSearchInstantSearchAdapter({
36+
client: client, // Elastic Path SDK client
37+
additionalSearchParameters: {
38+
// Additional search parameters can be configured here
39+
},
40+
})
41+
const searchClient = catalogSearchInstantSearchAdapter.searchClient
42+
```
43+
44+
## Project Structure
45+
46+
- `src/App.tsx`: Main search interface with InstantSearch components
47+
- `src/Autocomplete.tsx`: Custom autocomplete implementation with suggestions
48+
- `src/Hit.tsx`: Product hit component for displaying search results
49+
- `src/Panel.tsx`: Reusable panel component for facets
50+
- `src/RangeSlider.tsx`: Custom price range slider using Radix UI
51+
- `src/auth/StorefrontProvider.tsx`: Authentication setup (inherited from other examples)
52+
- `src/constants.ts`: Configuration including hierarchical attribute mapping
53+
54+
## Getting Started
55+
56+
### Prerequisites
57+
58+
- An Elastic Path Commerce Cloud account with Catalog Search enabled
59+
- A client ID for your storefront application
60+
- Node.js and pnpm (required package manager for this monorepo)
61+
62+
### Environment Variables
63+
64+
1. Copy the `.env.example` file to `.env` in the example directory:
65+
```bash
66+
cp .env.example .env
67+
```
68+
69+
2. Update the `.env` file with your Elastic Path credentials:
70+
```bash
71+
VITE_APP_EPCC_ENDPOINT_URL=your_endpoint_url # e.g. https://useast.api.elasticpath.com
72+
VITE_APP_EPCC_CLIENT_ID=your_client_id
73+
```
74+
75+
### Installation
76+
77+
Navigate to the example directory and install dependencies:
78+
79+
```bash
80+
cd examples/spa-search-instantsearch
81+
pnpm install
82+
```
83+
84+
### Development
85+
86+
To run the development server:
87+
88+
```bash
89+
pnpm dev
90+
```
91+
92+
Open [http://localhost:5173](http://localhost:5173) in your browser to see the search interface.
93+
94+
### Key Implementation Details
95+
96+
#### Search Client Configuration
97+
98+
The example uses the Elastic Path InstantSearch adapter to connect to your catalog:
99+
100+
```typescript
101+
import CatalogSearchInstantSearchAdapter from "@elasticpath/catalog-search-instantsearch-adapter"
102+
import { client } from "@epcc-sdk/sdks-shopper"
103+
104+
const catalogSearchInstantSearchAdapter = new CatalogSearchInstantSearchAdapter({
105+
client: client,
106+
additionalSearchParameters: {
107+
// Configure search parameters here
108+
},
109+
})
110+
```
111+
112+
#### Hierarchical Categories
113+
114+
Categories are configured for hierarchical navigation:
115+
116+
```typescript
117+
// src/constants.ts
118+
export const INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTES = [
119+
"extensions.products(categories).slug_path.lvl0",
120+
"extensions.products(categories).slug_path.lvl1",
121+
"extensions.products(categories).slug_path.lvl2",
122+
// ... additional levels as needed
123+
]
124+
```
125+
126+
#### Custom Components
127+
128+
- **Hit Component**: Displays individual product results with image, name, price, and description
129+
- **Autocomplete**: Implements search-as-you-type with recent searches and query suggestions
130+
- **Range Slider**: Custom price filter using Radix UI components
131+
132+
### Building for Production
133+
134+
To build the SPA for production:
135+
136+
```bash
137+
pnpm build
138+
```
139+
140+
This creates a `dist` folder with production-ready assets.
141+
142+
## Authentication
143+
144+
This example includes authentication setup using the `StorefrontProvider`, which handles:
145+
- Automatic token generation using implicit grant
146+
- Token storage in local storage
147+
- Automatic token refresh via SDK interceptors
148+
149+
Note: While authentication is implemented, it's not the focus of this example. For detailed authentication patterns, refer to the authentication-specific examples.
150+
151+
## Learn More
152+
153+
- [Elastic Path Catalog Search Documentation](https://documentation.elasticpath.com/commerce-cloud/docs/developer/how-to/search-catalog.html)
154+
- [InstantSearch.js Documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/)
155+
- [Elastic Path Composable Frontend](https://github.com/elasticpath/composable-frontend)
156+
- [React InstantSearch Components](https://www.algolia.com/doc/api-reference/widgets/react/)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import js from '@eslint/js'
2+
import globals from 'globals'
3+
import reactHooks from 'eslint-plugin-react-hooks'
4+
import reactRefresh from 'eslint-plugin-react-refresh'
5+
import tseslint from 'typescript-eslint'
6+
7+
export default tseslint.config(
8+
{ ignores: ['dist'] },
9+
{
10+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
11+
files: ['**/*.{ts,tsx}'],
12+
languageOptions: {
13+
ecmaVersion: 2020,
14+
globals: globals.browser,
15+
},
16+
plugins: {
17+
'react-hooks': reactHooks,
18+
'react-refresh': reactRefresh,
19+
},
20+
rules: {
21+
...reactHooks.configs.recommended.rules,
22+
'react-refresh/only-export-components': [
23+
'warn',
24+
{ allowConstantExport: true },
25+
],
26+
},
27+
},
28+
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Vite + React + TS</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "spa-search-instantsearch",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc -b && vite build",
9+
"lint": "eslint .",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"@algolia/autocomplete-js": "^1.19.2",
14+
"@algolia/autocomplete-plugin-query-suggestions": "^1.19.2",
15+
"@algolia/autocomplete-plugin-recent-searches": "^1.19.2",
16+
"@algolia/autocomplete-shared": "^1.19.2",
17+
"@algolia/autocomplete-theme-classic": "^1.19.2",
18+
"@elasticpath/catalog-search-instantsearch-adapter": "workspace:*",
19+
"@epcc-sdk/sdks-shopper": "workspace:*",
20+
"@radix-ui/react-slider": "^1.3.6",
21+
"algoliasearch": "^5.35.0",
22+
"instantsearch.css": "^8.5.1",
23+
"instantsearch.js": "^4.79.2",
24+
"react": "^19.1.0",
25+
"react-dom": "^19.1.0",
26+
"react-instantsearch": "^7.16.2"
27+
},
28+
"devDependencies": {
29+
"@eslint/js": "^9.25.0",
30+
"@types/react": "^19.1.2",
31+
"@types/react-dom": "^19.1.2",
32+
"@vitejs/plugin-react": "^4.4.1",
33+
"eslint": "^9.25.0",
34+
"eslint-plugin-react-hooks": "^5.2.0",
35+
"eslint-plugin-react-refresh": "^0.4.19",
36+
"globals": "^16.0.0",
37+
"typescript": "~5.8.3",
38+
"typescript-eslint": "^8.30.1",
39+
"vite": "^6.3.5"
40+
}
41+
}

0 commit comments

Comments
 (0)