Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(recommend): introduce Recommend widgets #6115

Merged
merged 41 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b66ed89
feat(recommend): map recommend results to widgets
aymeric-giraudet Apr 4, 2024
ddde6d2
feat(recommend): introduce `FrequentlyBoughtTogether` UI component (#…
raed667 Apr 15, 2024
6b45ef0
feat(recommend): introduce `RelatedProducts` UI component (#6129)
sarahdayan Apr 15, 2024
bcbd36c
feat(recommend): set up base CSS styles for `frequentlyBoughtTogether…
dhayab Apr 18, 2024
c40105d
feat(recommend): set up base CSS styles for `relatedProducts` widget …
dhayab Apr 22, 2024
8d6af5f
feat(recommend): introduce `connectRelatedProducts` connector (#6142)
sarahdayan Apr 22, 2024
879f8a6
feat(recommend): introduce `connectFrequentlyBoughtTogether` connecto…
raed667 Apr 23, 2024
8f0fa1f
feat(recommend): introduce `frequentlyBoughtTogether` widget (#6126)
dhayab Apr 23, 2024
8b91bbe
test(recommend): move `connectFrequentlyBoughtTogether` tests to CTS …
dhayab Apr 23, 2024
eef1468
test(recommend): setup CTS for `frequentlyBoughtTogether` (#6143)
dhayab Apr 24, 2024
865006b
feat(recommend): harmonize UI component for FBT and Related Products …
sarahdayan Apr 25, 2024
1278793
feat(recommend): introduce `relatedProducts` widget (#6154)
sarahdayan Apr 26, 2024
ee17419
feat(recommend): introduce `useRelatedProducts` Hook (#6159)
sarahdayan Apr 26, 2024
d2b2a4d
feat(recommend): introduce `<RelatedProducts>` widget (#6162)
sarahdayan Apr 26, 2024
aac6ebc
feat(recommend): handle multiple `objectIDs` for one widget (#6160)
aymeric-giraudet Apr 29, 2024
669f939
feat(recommend): introduce `TrendingItems` UI component (#6167)
dhayab Apr 29, 2024
b36cbf2
feat(recommend): introduce Frequently Bought Together React Hook and …
raed667 Apr 30, 2024
93b2eae
feat(recommend): enable multiple `objectIDs` in connectors (#6176)
aymeric-giraudet May 3, 2024
22ea4a5
feat(recommend): introduce `connectTrendingItems` connector (#6169)
dhayab May 3, 2024
186ccbe
feat(recommend): introduce `trendingItems` widget (#6171)
dhayab May 3, 2024
31612b8
feat(recommend): introduce `useTrendingItems` Hook (#6177)
Haroenv May 3, 2024
e95da12
feat(recommend): introduce `<TrendingItems>` widget (#6178)
Haroenv May 3, 2024
a83af36
test(recommend): enforce model in CTS
Haroenv May 3, 2024
844db3a
feat(recommend): cache results per `$$id` (#6181)
aymeric-giraudet May 6, 2024
29df464
feat(recommend): introduce `LookingSimilar` UI component (#6179)
Haroenv May 6, 2024
9ae1cf5
feat(recommend): introduce `connectLookingSimilar` connector (#6180)
Haroenv May 6, 2024
3a1ed9b
feat(recommend): introduce `lookingSimilar` widget (#6183)
Haroenv May 6, 2024
baf9ac3
feat(recommend): introduce Looking Similar React Hook and widget (#6184)
Haroenv May 6, 2024
6a2ea21
chore(recommend): rename tests for consistency
Haroenv May 7, 2024
b7c459a
chore(recommend): reference recommend widgets in exported types (#6186)
dhayab May 7, 2024
5b9d0e8
feat(recommend): rename `fallbackComponent` into `emptyComponent` (#6…
sarahdayan May 13, 2024
de8303e
chore(recommend): change error message
Haroenv May 14, 2024
f3301d4
refactor(recommend): clean recommend state when removing widgets (#6192)
dhayab May 14, 2024
6a38683
refactor(recommend): rename return type consistently to `items` (#6197)
Haroenv May 15, 2024
b952bcc
refactor(recommend): compute `classNames` only once (#6198)
Haroenv May 15, 2024
ff261a5
feat(recommend): support `escapeHTML` in recommend widgets (#6199)
dhayab May 15, 2024
93a2a4b
test(recommend): use shared mock client with recommendations in tests…
dhayab May 16, 2024
7a0f9e2
refactor(recommend): ensure unicity of recommend queries (#6203)
dhayab May 16, 2024
a58e01f
refactor(recommend): rename `maxRecommendations` to `limit` (#6196)
Haroenv May 16, 2024
b6d4f04
refactor(recommend): prevent network request (#6205)
Haroenv May 21, 2024
b9d90b5
chore: bump bundlesize
dhayab May 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ scripts/*/CHANGELOG.md
# private files
.env
.idea/
.vscode/

# Caches
.eslintcache
Expand Down
3 changes: 3 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ module.exports = (api) => {
// false positive (babel doesn't know types)
// this is actually only called on arrays
'String.prototype.includes',

// false positive (spread)
'Object.getOwnPropertyDescriptors',
];
if (defaultShouldInject && !exclude.includes(name)) {
throw new Error(
Expand Down
20 changes: 10 additions & 10 deletions bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,35 @@
"files": [
{
"path": "packages/algoliasearch-helper/dist/algoliasearch.helper.js",
"maxSize": "40.25 kB"
"maxSize": "41.25 kB"
},
{
"path": "packages/algoliasearch-helper/dist/algoliasearch.helper.min.js",
"maxSize": "12.75 kB"
"maxSize": "13.25 kB"
},
{
"path": "./packages/instantsearch.js/dist/instantsearch.production.min.js",
"maxSize": "77.75 kB"
"maxSize": "81.5 kB"
},
{
"path": "./packages/instantsearch.js/dist/instantsearch.development.js",
"maxSize": "171.25 kB"
"maxSize": "177.25 kB"
},
{
"path": "packages/react-instantsearch-core/dist/umd/ReactInstantSearchCore.min.js",
"maxSize": "48.5 kB"
"maxSize": "50 kB"
},
{
"path": "packages/react-instantsearch/dist/umd/ReactInstantSearch.min.js",
"maxSize": "59.5 kB"
"maxSize": "62.75 kB"
},
{
"path": "packages/vue-instantsearch/vue2/umd/index.js",
"maxSize": "66.75 kB"
"maxSize": "67.25 kB"
},
{
"path": "packages/vue-instantsearch/vue3/umd/index.js",
"maxSize": "67 kB"
"maxSize": "67.75 kB"
},
{
"path": "packages/vue-instantsearch/vue2/cjs/index.js",
Expand All @@ -54,11 +54,11 @@
},
{
"path": "./packages/instantsearch.css/themes/reset-min.css",
"maxSize": "1 kB"
"maxSize": "1.25 kB"
},
{
"path": "./packages/instantsearch.css/themes/satellite.css",
"maxSize": "4.5 kB"
"maxSize": "4.60 kB"
},
{
"path": "./packages/instantsearch.css/themes/satellite-min.css",
Expand Down
4 changes: 2 additions & 2 deletions examples/js/getting-started/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"version": "1.3.0",
"private": true,
"scripts": {
"start": "BABEL_ENV=parcel parcel index.html --port 3000",
"build": "BABEL_ENV=parcel parcel build index.html",
"start": "BABEL_ENV=parcel parcel index.html products.html --port 3000",
"build": "BABEL_ENV=parcel parcel build index.html products.html",
"lint": "eslint .",
"lint:fix": "npm run lint -- --fix"
},
Expand Down
44 changes: 44 additions & 0 deletions examples/js/getting-started/products.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />

<link rel="shortcut icon" href="./favicon.png" />

<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/instantsearch.css@7/themes/satellite-min.css"
/>
<link rel="stylesheet" href="./src/index.css" />
<link rel="stylesheet" href="./src/app.css" />

<title>InstantSearch.js — Getting started</title>
</head>

<body>
<header class="header">
<h1 class="header-title">
<a href="/">Getting started</a>
</h1>
<p class="header-subtitle">
using
<a href="https://github.com/algolia/instantsearch">
InstantSearch.js
</a>
</p>
</header>

<div class="container">
<a href="/">← Back to search</a>
<div id="hits"></div>
<div id="related-products"></div>
</div>

<script type="module" src="./src/products.js"></script>
</body>
</html>
40 changes: 40 additions & 0 deletions examples/js/getting-started/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,43 @@
margin: 2rem auto;
text-align: center;
}

#related-products,
.ais-Hits--single {
margin-top: 1rem;
}

.ais-Hits--single article {
display: flex;
gap: 1rem;
}

.ais-Hits--single img {
width: 150px;
height: 150px;
object-fit: contain;
flex-shrink: 0;
}

.ais-RelatedProducts-list {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
}

.ais-RelatedProducts-item {
align-items: start;
}

.ais-RelatedProducts-item img {
width: 100%;
height: 100px;
object-fit: contain;
}

.ais-RelatedProducts-item article {
display: flex;
flex-direction: column;
height: 100%;
justify-content: space-between;
}
7 changes: 6 additions & 1 deletion examples/js/getting-started/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,13 @@ search.addWidgets([
templates: {
item: (hit, { html, components }) => html`
<article>
<h1>${components.Highlight({ hit, attribute: 'name' })}</h1>
<h1>
<a href="/products.html?pid=${hit.objectID}"
>${components.Highlight({ hit, attribute: 'name' })}</a
>
</h1>
<p>${components.Highlight({ hit, attribute: 'description' })}</p>
<a href="/products.html?pid=${hit.objectID}">See product</a>
</article>
`,
},
Expand Down
58 changes: 58 additions & 0 deletions examples/js/getting-started/src/products.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import algoliasearch from 'algoliasearch/lite';
import instantsearch from 'instantsearch.js';
import { configure, hits, relatedProducts } from 'instantsearch.js/es/widgets';

const searchParams = new URLSearchParams(document.location.search);

const pid = searchParams.get('pid');

const searchClient = algoliasearch(
'latency',
'6be0576ff61c053d5f9a3225e2a90f76'
);

const search = instantsearch({
indexName: 'instant_search',
searchClient,
insights: true,
});

search.addWidgets([
hits({
container: '#hits',
templates: {
item: (hit, { html, components }) => html`
<article>
<img src="${hit.image}" />
<div>
<h1>${components.Highlight({ hit, attribute: 'name' })}</h1>
<p>${components.Highlight({ hit, attribute: 'description' })}</p>
</div>
</article>
`,
},
cssClasses: { root: 'ais-Hits--single' },
}),
relatedProducts({
container: '#related-products',
objectIDs: [pid],
maxRecommendations: 4,
templates: {
item: (hit, { html }) => html`
<article>
<div>
<img src="${hit.image}" />
<h2>${hit.name}</h2>
</div>
<a href="/products.html?pid=${hit.objectID}">See product</a>
</article>
`,
},
}),
configure({
hitsPerPage: 1,
filters: `objectID:${pid}`,
}),
]);

search.start();
35 changes: 25 additions & 10 deletions packages/algoliasearch-helper/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
RelatedProductsQuery as RecommendRelatedProductsQuery,
TrendingFacetsQuery as RecommendTrendingFacetsQuery,
TrendingItemsQuery as RecommendTrendingItemsQuery,
RecommendQueriesResponse,
} from '@algolia/recommend';

/**
Expand All @@ -42,7 +43,7 @@ declare namespace algoliasearchHelper {
state: SearchParameters;
recommendState: RecommendParameters;
lastResults: SearchResults | null;
lastRecommendResults: unknown | null; // TODO: Define type in dedicated PR
lastRecommendResults: RecommendResults | null;
derivedHelpers: DerivedHelper[];

on(
Expand Down Expand Up @@ -309,11 +310,11 @@ declare namespace algoliasearchHelper {
*/
removeExclude(facet: string, value: string): this;
removeTag(value: string): this;
removeFrequentlyBoughtTogether(id: string): this;
removeRelatedProducts(id: string): this;
removeTrendingItems(id: string): this;
removeTrendingFacets(id: string): this;
removeLookingSimilar(id: string): this;
removeFrequentlyBoughtTogether(id: number): this;
removeRelatedProducts(id: number): this;
removeTrendingItems(id: number): this;
removeTrendingFacets(id: number): this;
removeLookingSimilar(id: number): this;
toggleFacetExclusion(facet: string, value: string): this;
/**
* @deprecated since version 2.4.0, see {@link AlgoliaSearchHelper#toggleFacetExclusion}
Expand Down Expand Up @@ -402,15 +403,15 @@ declare namespace algoliasearchHelper {
event: 'recommend:result',
cb: (res: {
recommend: {
results: unknown | null; // TODO: Define type in dedicated PR
results: RecommendResults | null;
state: RecommendParameters;
};
}) => void
): this;
on(event: 'error', cb: (res: { error: Error }) => void): this;

lastResults: SearchResults | null;
lastRecommendResults: unknown | null; // TODO: Define type in dedicated PR
lastRecommendResults: RecommendResults | null;
detach(): void;
getModifiedState(): SearchParameters;
getModifiedRecommendState(): RecommendParameters;
Expand Down Expand Up @@ -1568,7 +1569,7 @@ declare namespace algoliasearchHelper {
export type RecommendParametersWithId<
T extends PlainRecommendParameters = PlainRecommendParameters
> = T & {
$$id: string;
$$id: number;
};

export type RecommendParametersOptions = {
Expand All @@ -1579,7 +1580,7 @@ declare namespace algoliasearchHelper {
params: RecommendParametersWithId[];
constructor(opts?: RecommendParametersOptions);
addParams(params: RecommendParametersWithId): RecommendParameters;
removeParams(id: string): RecommendParameters;
removeParams(id: number): RecommendParameters;
addFrequentlyBoughtTogether(
params: RecommendParametersWithId<FrequentlyBoughtTogetherQuery>
): RecommendParameters;
Expand All @@ -1596,6 +1597,20 @@ declare namespace algoliasearchHelper {
params: RecommendParametersWithId<LookingSimilarQuery>
): RecommendParameters;
}

type RecommendResponse<TObject> =
RecommendQueriesResponse<TObject>['results'];

type RecommendResultItem<TObject = any> = RecommendResponse<TObject>[0];

export class RecommendResults<T = any> {
constructor(state: RecommendParameters, results: RecommendResponse<T>);

_state: RecommendParameters;
_rawResults: RecommendResponse<T>;

[index: number]: RecommendResultItem<T>;
dhayab marked this conversation as resolved.
Show resolved Hide resolved
}
}

export = algoliasearchHelper;
25 changes: 11 additions & 14 deletions packages/algoliasearch-helper/src/RecommendParameters/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,8 @@ RecommendParameters.prototype = {

addParams: function (params) {
var newParams = this.params.slice();
var existingParamsIndex = this.params.findIndex(function (currentParams) {
return currentParams.$$id === params.$$id;
});

if (existingParamsIndex !== -1) {
newParams.splice(existingParamsIndex, 1, params);
} else {
newParams.push(params);
}
newParams.push(params);

return new RecommendParameters({ params: newParams });
},
Expand Down Expand Up @@ -74,13 +67,17 @@ RecommendParameters.prototype = {
);
},

_buildQueries: function (indexName) {
return this.params.map(function (params) {
var query = Object.assign({}, params, { indexName: indexName });
delete query.$$id;
_buildQueries: function (indexName, cache) {
return this.params
.filter(function (params) {
return cache[params.$$id] === undefined;
})
.map(function (params) {
var query = Object.assign({}, params, { indexName: indexName });
delete query.$$id;

return query;
});
return query;
});
},
};

Expand Down