Skip to content

Commit

Permalink
Merge pull request #985 from searchspring/develop
Browse files Browse the repository at this point in the history
Release v0.51.0
  • Loading branch information
korgon authored Jan 22, 2024
2 parents cb61b95 + 76eec59 commit 9d4c607
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 24 deletions.
5 changes: 3 additions & 2 deletions docs/INTEGRATION_RECOMMENDATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ Context variables may be applied to individual recommendation profiles similar t

| Option | Value | Page | Description |
|---|---|:---:|---|
| product | current product sku | product detail page | used to identify the current product being viewed |
| products | array of SKU strings | product detail page | SKU value(s) to identify the current product(s) being viewed |
| cart | array (or function that returns an array) of current cart skus | all | optional method of setting cart contents |
| options.siteId | global siteId overwrite | all | optional global siteId overwrite |
| options.categories | array of category path strings | all | optional category identifiers used in category trending recommendation profiles |
| options.brands | array of brand strings | all | optional brand identifiers used in brand trending recommendation profiles |
| options.branch | template branch overwrite | all | optional branch overwrite for recommendations template (advanced usage) |
| options.filters | array of filters | all | optional recommendation filters |
| options.blockedItems | array of strings | all | SKU values to identify which products to exclude from the response |
| options.batched | boolean (default: `true`)| all | only applies to recommendation context, optional disable profile from being batched in a single request, can also be set globally [via config](https://github.com/searchspring/snap/tree/main/packages/snap-controller/src/Recommendation) |
| options.order | number | all | optional order number for recommendation params to be added to the batched request. Profiles that do not specify an order will be placed at the end, in the occurrence they appear in the DOM.
| options.limit | number (default: 20, max: 20) | all | optional maximum number of results to display, can also be set globally [via config globals](https://github.com/searchspring/snap/tree/main/packages/snap-controller/src/Recommendation) |
Expand All @@ -35,7 +36,7 @@ A typical "similar" profile that would display products similar to the product p

```html
<script type="searchspring/recommend" profile="customers-also-viewed">
product = 'product123';
products = ['product123'];
</script>
```

Expand Down
2 changes: 1 addition & 1 deletion packages/snap-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ const client = new Client(globals, clientConfig);
const results = await client.recommend({
tag: 'similar',
siteId: 'abc123',
product: 'product123',
products: ['product123'],
shopper: 'snapdev',
});
```
46 changes: 44 additions & 2 deletions packages/snap-client/src/Client/apis/Recommend.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { ApiConfiguration } from './Abstract';
import { RecommendAPI } from './Recommend';
import { MockData } from '@searchspring/snap-shared';

import type { RecommendRequestModel } from '../../types';

const mockData = new MockData();

const wait = (time?: number) => {
Expand Down Expand Up @@ -134,7 +136,7 @@ describe('Recommend Api', () => {
headers: {},
};

const batchParams = {
const batchParams: Partial<RecommendRequestModel> = {
siteId: '8uyt2m',
lastViewed: [
'marnie-runner-2-7x10',
Expand All @@ -153,7 +155,7 @@ describe('Recommend Api', () => {
'dayna-4x6',
'moema-4x6',
],
product: ['marnie-runner-2-7x10'],
product: 'marnie-runner-2-7x10',
};

it('batchRecommendations batches as expected', async () => {
Expand Down Expand Up @@ -418,6 +420,46 @@ describe('Recommend Api', () => {
requestMock.mockReset();
});

it('batchRecommendations will combine `product` and `products` params into `products` when used together', async () => {
const api = new RecommendAPI(new ApiConfiguration({}));

const requestMock = jest
.spyOn(global.window, 'fetch')
.mockImplementation(() => Promise.resolve({ status: 200, json: () => Promise.resolve(mockData.recommend()) } as Response));

const requestURL =
'https://8uyt2m.a.searchspring.io/boost/8uyt2m/recommend?tags=crossSell&limits=20&products=some_sku&products=some_sku2&products=marnie-runner-2-7x10&siteId=8uyt2m&lastViewed=marnie-runner-2-7x10&lastViewed=ruby-runner-2-7x10&lastViewed=abbie-runner-2-7x10&lastViewed=riley-4x6&lastViewed=joely-5x8&lastViewed=helena-4x6&lastViewed=kwame-4x6&lastViewed=sadie-4x6&lastViewed=candice-runner-2-7x10&lastViewed=esmeray-4x6&lastViewed=camilla-230x160&lastViewed=candice-4x6&lastViewed=sahara-4x6&lastViewed=dayna-4x6&lastViewed=moema-4x6';

// @ts-ignore
api.batchRecommendations({ tags: ['crossSell'], products: ['some_sku', 'some_sku2'], ...batchParams });

//add delay for paramBatch.timeout
await wait(250);

expect(requestMock).toHaveBeenCalledWith(requestURL, GETParams);
requestMock.mockReset();
});

it('batchRecommendations will utilize the `blockedItems` parameter when provided', async () => {
const api = new RecommendAPI(new ApiConfiguration({}));

const requestMock = jest
.spyOn(global.window, 'fetch')
.mockImplementation(() => Promise.resolve({ status: 200, json: () => Promise.resolve(mockData.recommend()) } as Response));

const requestURL =
'https://8uyt2m.a.searchspring.io/boost/8uyt2m/recommend?tags=undefined&limits=20&blockedItems=blocked_sku1&blockedItems=blocked_sku2&siteId=8uyt2m&lastViewed=marnie-runner-2-7x10&lastViewed=ruby-runner-2-7x10&lastViewed=abbie-runner-2-7x10&lastViewed=riley-4x6&lastViewed=joely-5x8&lastViewed=helena-4x6&lastViewed=kwame-4x6&lastViewed=sadie-4x6&lastViewed=candice-runner-2-7x10&lastViewed=esmeray-4x6&lastViewed=camilla-230x160&lastViewed=candice-4x6&lastViewed=sahara-4x6&lastViewed=dayna-4x6&lastViewed=moema-4x6&product=marnie-runner-2-7x10';

// @ts-ignore
api.batchRecommendations({ blockedItems: ['blocked_sku1', 'blocked_sku2'], ...batchParams });

//add delay for paramBatch.timeout
await wait(250);

expect(requestMock).toHaveBeenCalledWith(requestURL, GETParams);
requestMock.mockReset();
});

it('batchRecommendations handles POST requests', async () => {
const api = new RecommendAPI(new ApiConfiguration({}));

Expand Down
7 changes: 7 additions & 0 deletions packages/snap-client/src/Client/apis/Recommend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ export class RecommendAPI extends API {

batch.request.limits = (batch.request.limits as number[]).concat(limits);
batch.request = { ...batch.request, ...otherParams };

// combine product data if both 'product' and 'products' are used
if (batch.request.product && Array.isArray(batch.request.products)) {
batch.request.products = batch.request.products.concat(batch.request.product);

delete batch.request.product;
}
});

try {
Expand Down
2 changes: 1 addition & 1 deletion packages/snap-client/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './Client/Client';

export { ClientGlobals, ClientConfig, TrendingResponseModel, RecommendCombinedResponseModel } from './types';
export { ClientGlobals, ClientConfig, TrendingResponseModel, RecommendCombinedRequestModel, RecommendCombinedResponseModel } from './types';
4 changes: 4 additions & 0 deletions packages/snap-client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export type RecommendRequestModel = {
tags: string[];
siteId: string;
product?: string;
products?: string[];
shopper?: string;
categories?: string[];
brands?: string[];
Expand All @@ -109,6 +110,7 @@ export type RecommendRequestModel = {
limits?: number | number[];
order?: number;
filters?: RecommendationRequestFilterModel[];
blockedItems?: string[];
};

export type GetRecommendRequestModel = Omit<RecommendRequestModel, 'filters'> & {
Expand Down Expand Up @@ -164,6 +166,7 @@ export type RecommendCombinedRequestModel = {
tag: string;
siteId: string;
product?: string;
products?: string[];
shopper?: string;
categories?: string[];
brands?: string[];
Expand All @@ -172,6 +175,7 @@ export type RecommendCombinedRequestModel = {
test?: boolean;
branch?: string;
filters?: RecommendationRequestFilterModel[];
blockedItems?: string[];
};

export type RecommendationRequestFilterModel = RecommendationRequestRangeFilterModel | RecommendationRequestValueFilterModel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const defaultConfig: AutocompleteControllerConfig = {
},
redirects: {
merchandising: true,
singleResult: true,
singleResult: false,
},
},
};
Expand Down
2 changes: 1 addition & 1 deletion packages/snap-controller/src/Autocomplete/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The `AutocompleteController` is used when making queries to the API `autocomplet
| settings.history.limit | when set, historical (previously searched) queries will be fetched and made available in the history store || |
| settings.history.showResults | if history limit is set and there is no input, the first term results will be displayed | false | |
| settings.redirects.merchandising | boolean to disable merchandising redirects when ac form is submitted | true | |
| settings.redirects.singleResult | enable redirect to product detail page if search yields 1 result count | true | |
| settings.redirects.singleResult | enable redirect to product detail page if search yields 1 result count | false | |

<br>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ControllerTypes } from '../types';
import type { ProductViewEvent } from '@searchspring/snap-tracker';
import type { RecommendationStore } from '@searchspring/snap-store-mobx';
import type { Next } from '@searchspring/snap-event-manager';
import type { RecommendCombinedRequestModel } from '@searchspring/snap-client';
import type { RecommendationControllerConfig, BeforeSearchObj, AfterStoreObj, ControllerServices, ContextVariables } from '../types';

type RecommendationTrackMethods = {
Expand All @@ -21,19 +22,6 @@ type RecommendationTrackMethods = {
render: (results?: Product[]) => BeaconEvent | undefined;
};

type RecommendCombinedRequestModel = {
tag: string;
siteId: string;
product?: string;
shopper?: string;
categories?: string[];
brands?: string[];
cart?: string[];
lastViewed?: string[];
test?: boolean;
branch?: string;
};

const defaultConfig: RecommendationControllerConfig = {
id: 'recommend',
tag: '',
Expand Down Expand Up @@ -288,7 +276,7 @@ export class RecommendationController extends AbstractController {
})();

get params(): RecommendCombinedRequestModel {
const params = {
const params: RecommendCombinedRequestModel = {
tag: this.config.tag,
batched: this.config.batched,
branch: this.config.branch || 'production',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,12 @@ export class RecommendationInstantiator {
const contextGlobals: any = {};

const elemContext = getContext(
['shopperId', 'shopper', 'product', 'seed', 'cart', 'options', 'profile', 'custom'],
['shopperId', 'shopper', 'product', 'products', 'seed', 'cart', 'options', 'profile', 'custom'],
elem as HTMLScriptElement
);
const context: ContextVariables = deepmerge(this.context, elemContext);

const { shopper, shopperId, product, seed, cart, options } = context;
const { shopper, shopperId, product, products, seed, cart, options } = context;

/*
type instantiatorContext = {
Expand All @@ -138,6 +138,7 @@ export class RecommendationInstantiator {
};
shopperId?: string;
product?: string;
products?: string[];
seed?: string;
cart?: string[] | () => string[];
options?: {
Expand All @@ -146,6 +147,7 @@ export class RecommendationInstantiator {
batched?: boolean;
realtime?: boolean;
categories?: string[];
blockedItems?: string[];
brands?: string[];
limit?: number;
}
Expand All @@ -158,6 +160,11 @@ export class RecommendationInstantiator {
if (product || seed) {
contextGlobals.product = product || seed;
}
if (products) {
contextGlobals.products = products;
}

// options
if (options?.branch) {
contextGlobals.branch = options.branch;
}
Expand All @@ -176,6 +183,10 @@ export class RecommendationInstantiator {
if (options?.limit && Number.isInteger(Number(options?.limit))) {
contextGlobals.limits = Number(options?.limit);
}
if (options?.blockedItems && Array.isArray(options.blockedItems)) {
contextGlobals.blockedItems = options.blockedItems;
}

let cartContents;
if (typeof cart === 'function') {
try {
Expand Down

0 comments on commit 9d4c607

Please sign in to comment.