Skip to content

Commit

Permalink
DCONN-77: Allow additional API parameters for recommendations
Browse files Browse the repository at this point in the history
  • Loading branch information
lachire committed Oct 22, 2024
1 parent ed6ac0c commit 1c11103
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 12 deletions.
6 changes: 6 additions & 0 deletions packages/frontend/vanilla-js/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to this project will be documented in this file.

## [3.1.4] - 2024-10-08

### Changed

Support additional parameters for Recommendations widgets.

## [3.1.3] - 2024-10-08

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/vanilla-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bloomreach/discovery-ui-js",
"version": "3.1.3",
"version": "3.1.4",
"main": "index.js",
"type": "module",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
RecommendationsTemplateData,
} from '../../types';
import * as listeners from '../../listeners/recommendations';
import { buildRecommendationsConfig, extractSegmentationCookie, isMobileView, isTabletView } from '../../utils';
import { buildRecommendationsConfig, extractSegmentationCookie, formatAdditionalParams, isMobileView, isTabletView } from '../../utils';
import {
COOKIE_NAME_SEGMENTATION_CUSTOMER_PROFILE,
DEFAULT_PAGE_SIZE,
Expand Down Expand Up @@ -143,21 +143,31 @@ function buildApiCallParameters(widgetNode: Node): GetWidgetRequest {
const urlParameters = new URLSearchParams(window.location.search as string);
const currentRecommendationsRequestState = getCurrentRecommendationsRequestState();

const widgetAttributes: DOMStringMap = (widgetNode as HTMLElement).dataset;
const {
id,
type,
categoryId,
query,
itemIds,
userId,
numberOfItemsToFetch,
additionalParams,
}: DOMStringMap = (widgetNode as HTMLElement).dataset;

const apiParameters: WidgetRequestType = {
...(config?.widget?.endpoint ? { endpoint: config.widget.endpoint } : {}),
...(config?.widget?.fields ? { fields: config.widget.fields } : {}),
type: widgetAttributes.type as WidgetTypes,
id: widgetAttributes.id ?? '',
type: type as WidgetTypes,
id: id ?? '',
account_id: config.account_id,
domain_key: config.domain_key,
request_id: currentRecommendationsRequestState.request_id,
_br_uid_2: config.tracking_cookie ?? '',
ref_url: config.ref_url ?? '',
url: config.url ?? '',
rows: Number(widgetAttributes.numberOfItemsToFetch) || DEFAULT_PAGE_SIZE,
rows: Number(numberOfItemsToFetch) || DEFAULT_PAGE_SIZE,
start: DEFAULT_START,
...formatAdditionalParams(additionalParams)
};

// add URL parameters
Expand All @@ -178,15 +188,15 @@ function buildApiCallParameters(widgetNode: Node): GetWidgetRequest {

// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
if (isKeywordWidgetRequest(apiParameters)) {
apiParameters.query = widgetAttributes.query ?? '';
apiParameters.query = query ?? '';
} else if (isCategoryWidgetRequest(apiParameters)) {
apiParameters.cat_id = widgetAttributes.categoryId ?? '';
apiParameters.cat_id = categoryId ?? '';
} else if (isItemWidgetRequest(apiParameters)) {
apiParameters.item_ids = widgetAttributes.itemIds;
apiParameters.item_ids = itemIds;
} else if (isPersonalizedWidgetRequest(apiParameters)) {
apiParameters.user_id = widgetAttributes.userId;
apiParameters.user_id = userId;
} else if (!isGlobalWidgetRequest(apiParameters)) {
throw new Error(`Invalid widget type: "${widgetAttributes.type}"`);
throw new Error(`Invalid widget type: "${type}"`);
}

return apiParameters;
Expand Down
15 changes: 15 additions & 0 deletions packages/frontend/vanilla-js/src/utils/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,18 @@ export function getSelectedColors(): string[] {
[]
);
}

export function formatAdditionalParams(additionalParams?: string | null): Record<string, any> {
return additionalParams?.replaceAll('&quot;', '"')
.split(/&(?!#\d+;|#x[\da-fA-F]+;|[a-zA-Z]+;)/) // matches standalone '&', but excludes those that are part of HTML entities
.reduce<Record<string, any>>((accu, curr) => {
const index = curr.indexOf('=');
if (index > 0) {
const key = curr.slice(0, index);
const value = curr.slice(index + 1);
accu[key] = value;
}

return accu;
}, {}) ?? {};
}
2 changes: 1 addition & 1 deletion packages/frontend/vanilla-js/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
],

/* Basic Options */
"target": "ES2017",
"target": "ES2022",
"module": "esnext" ,
"moduleResolution": "node",
"allowJs": false,
Expand Down

0 comments on commit 1c11103

Please sign in to comment.