Skip to content

Commit

Permalink
feat(insights): set algolia credentials per event when supported
Browse files Browse the repository at this point in the history
  • Loading branch information
dhayab committed Apr 13, 2023
1 parent 28d8b81 commit c8fdd1f
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { AlgoliaInsightsHit, ClickedObjectIDsAfterSearchParams } from './types';
import type {
AlgoliaInsightsHit,
ClickedObjectIDsAfterSearchParams,
InsightsParamsWithItems,
} from './types';

type CreateClickedEventParams = {
item: AlgoliaInsightsHit;
Expand All @@ -9,12 +13,12 @@ export function createClickedEvent({
item,
items,
}: CreateClickedEventParams): Omit<
ClickedObjectIDsAfterSearchParams,
InsightsParamsWithItems<ClickedObjectIDsAfterSearchParams>,
'eventName'
> & { algoliaSource?: string[] } {
return {
index: item.__autocomplete_indexName,
objectIDs: [item.objectID],
items: [item],
positions: [1 + items.findIndex((x) => x.objectID === item.objectID)],
queryID: item.__autocomplete_queryID,
algoliaSource: ['autocomplete'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import type { InsightsMethodMap } from 'search-insights';

import { isModernInsightsClient } from './isModernInsightsClient';
import {
AlgoliaInsightsHit,
ClickedFiltersParams,
ClickedObjectIDsAfterSearchParams,
ClickedObjectIDsParams,
ConvertedFiltersParams,
ConvertedObjectIDsAfterSearchParams,
ConvertedObjectIDsParams,
InsightsClient,
InsightsClientMethod,
InsightsParamsWithItems,
ViewedFiltersParams,
ViewedObjectIDsParams,
} from './types';
Expand All @@ -24,7 +30,39 @@ function chunk<TItem extends { objectIDs: string[] }>(
return chunks;
}

function mapToInsightsParamsApi<
TInsightsParamsType extends {
items: AlgoliaInsightsHit[];
objectIDs?: string[];
}
>(params: TInsightsParamsType[]) {
return params.map(({ items, ...param }) => ({
...param,
objectIDs: items?.map(({ objectID }) => objectID) || param.objectIDs,
}));
}

export function createSearchInsightsApi(searchInsights: InsightsClient) {
const canSendHeaders = isModernInsightsClient(searchInsights);

function sendToInsights<TInsightsMethod extends InsightsClientMethod>(
method: InsightsClientMethod,
payloads: InsightsMethodMap[TInsightsMethod],
items?: AlgoliaInsightsHit[]
) {
if (canSendHeaders && typeof items !== 'undefined') {
const { appId, apiKey } = items[0].__autocomplete_algoliaCredentials;
const headers = {
'X-Algolia-Application-Id': appId,
'X-Algolia-API-Key': apiKey,
};

searchInsights(method, ...payloads, { headers } as any);
} else {
searchInsights(method, ...payloads);
}
}

return {
/**
* Initializes Insights with Algolia credentials.
Expand All @@ -44,20 +82,32 @@ export function createSearchInsightsApi(searchInsights: InsightsClient) {
* @link https://www.algolia.com/doc/api-reference/api-methods/clicked-object-ids-after-search/
*/
clickedObjectIDsAfterSearch(
...params: ClickedObjectIDsAfterSearchParams[]
...params: Array<
InsightsParamsWithItems<ClickedObjectIDsAfterSearchParams>
>
) {
if (params.length > 0) {
searchInsights('clickedObjectIDsAfterSearch', ...params);
sendToInsights(
'clickedObjectIDsAfterSearch',
mapToInsightsParamsApi(params),
params[0].items
);
}
},
/**
* Sends click events to capture clicked items.
*
* @link https://www.algolia.com/doc/api-reference/api-methods/clicked-object-ids/
*/
clickedObjectIDs(...params: ClickedObjectIDsParams[]) {
clickedObjectIDs(
...params: Array<InsightsParamsWithItems<ClickedObjectIDsParams>>
) {
if (params.length > 0) {
searchInsights('clickedObjectIDs', ...params);
sendToInsights(
'clickedObjectIDs',
mapToInsightsParamsApi(params),
params[0].items
);
}
},
/**
Expand All @@ -76,20 +126,32 @@ export function createSearchInsightsApi(searchInsights: InsightsClient) {
* @link https://www.algolia.com/doc/api-reference/api-methods/converted-object-ids-after-search/
*/
convertedObjectIDsAfterSearch(
...params: ConvertedObjectIDsAfterSearchParams[]
...params: Array<
InsightsParamsWithItems<ConvertedObjectIDsAfterSearchParams>
>
) {
if (params.length > 0) {
searchInsights('convertedObjectIDsAfterSearch', ...params);
sendToInsights(
'convertedObjectIDsAfterSearch',
mapToInsightsParamsApi(params),
params[0].items
);
}
},
/**
* Sends conversion events to capture clicked items.
*
* @link https://www.algolia.com/doc/api-reference/api-methods/converted-object-ids/
*/
convertedObjectIDs(...params: ConvertedObjectIDsParams[]) {
convertedObjectIDs(
...params: Array<InsightsParamsWithItems<ConvertedObjectIDsParams>>
) {
if (params.length > 0) {
searchInsights('convertedObjectIDs', ...params);
sendToInsights(
'convertedObjectIDs',
mapToInsightsParamsApi(params),
params[0].items
);
}
},
/**
Expand All @@ -107,14 +169,31 @@ export function createSearchInsightsApi(searchInsights: InsightsClient) {
*
* @link https://www.algolia.com/doc/api-reference/api-methods/viewed-object-ids/
*/
viewedObjectIDs(...params: ViewedObjectIDsParams[]) {
viewedObjectIDs(
...params: Array<InsightsParamsWithItems<ViewedObjectIDsParams>>
) {
if (params.length > 0) {
params
.map((param) => ({
...param,
objectIDs:
param.items?.map(({ objectID }) => objectID) || param.objectIDs,
}))
.reduce(
(acc, param) => [...acc, ...chunk<ViewedObjectIDsParams>(param)],
[] as ViewedObjectIDsParams[]
(acc, { items, ...param }) => [
...acc,
...chunk<ViewedObjectIDsParams>(param).map((payload) => {
return { items, payload };
}),
],
[] as Array<{
items?: AlgoliaInsightsHit[];
payload: ViewedObjectIDsParams;
}>
)
.forEach((param) => searchInsights('viewedObjectIDs', param));
.forEach(({ items, payload }) =>
sendToInsights('viewedObjectIDs', [payload], items)
);
}
},
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
import { AlgoliaInsightsHit, ViewedObjectIDsParams } from './types';
import {
AlgoliaInsightsHit,
InsightsParamsWithItems,
ViewedObjectIDsParams,
} from './types';

type CreateViewedEventsParams = {
items: AlgoliaInsightsHit[];
};

export function createViewedEvents({
items,
}: CreateViewedEventsParams): Array<Omit<ViewedObjectIDsParams, 'eventName'>> {
const objectIDsByIndexName = items.reduce<Record<string, string[]>>(
}: CreateViewedEventsParams): Array<
Omit<InsightsParamsWithItems<ViewedObjectIDsParams>, 'eventName'>
> {
const itemsByIndexName = items.reduce<Record<string, AlgoliaInsightsHit[]>>(
(acc, current) => {
acc[current.__autocomplete_indexName] = (
acc[current.__autocomplete_indexName] ?? []
).concat(current.objectID);
).concat(current);

return acc;
},
{}
);

return Object.keys(objectIDsByIndexName).map((indexName) => {
const objectIDs = objectIDsByIndexName[indexName];
return Object.keys(itemsByIndexName).map((indexName) => {
const items = itemsByIndexName[indexName];

return {
index: indexName,
objectIDs,
items,
algoliaSource: ['autocomplete'],
};
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { InsightsClient } from './types';

export function isModernInsightsClient(client: InsightsClient): boolean {
const [major, minor] = (client.version || '').split('.').map(Number);

/* eslint-disable @typescript-eslint/camelcase */
const v3 = major >= 3;
const v2_4 = major === 2 && minor >= 4;
const v1_10 = major === 1 && minor >= 10;

return v3 || v2_4 || v1_10;
/* eslint-enable @typescript-eslint/camelcase */
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import { createSearchInsightsApi } from '../createSearchInsightsApi';

import type { AlgoliaInsightsHit } from './AlgoliaInsightsHit';

export type AutocompleteInsightsApi = ReturnType<
typeof createSearchInsightsApi
>;

export type InsightsParamsWithItems<
TParams extends { objectIDs: string[] }
> = Omit<TParams, 'objectIDs'> & {
items: AlgoliaInsightsHit[];
/**
* @deprecated use `items` instead
*/
objectIDs?: string[];
};

export type ClickedObjectIDsAfterSearchParams = {
eventName: string;
index: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import { AutocompleteState } from '@algolia/autocomplete-js';
import type { AutocompleteState } from '@algolia/autocomplete-js';

import {
import type {
ClickedObjectIDsAfterSearchParams,
InsightsParamsWithItems,
ViewedObjectIDsParams,
} from './AutocompleteInsightsApi';

import { AlgoliaInsightsHit, AutocompleteInsightsApi } from '.';
import type { AlgoliaInsightsHit, AutocompleteInsightsApi } from '.';

export type OnSelectParams = {
insights: AutocompleteInsightsApi;
insightsEvents: Array<
ClickedObjectIDsAfterSearchParams & { algoliaSource?: string[] }
InsightsParamsWithItems<
ClickedObjectIDsAfterSearchParams & {
algoliaSource?: string[];
}
>
>;
item: AlgoliaInsightsHit;
state: AutocompleteState<any>;
Expand All @@ -21,6 +26,10 @@ export type OnActiveParams = OnSelectParams;

export type OnItemsChangeParams = {
insights: AutocompleteInsightsApi;
insightsEvents: Array<ViewedObjectIDsParams & { algoliaSource?: string[] }>;
insightsEvents: Array<
InsightsParamsWithItems<
ViewedObjectIDsParams & { algoliaSource?: string[] }
>
>;
state: AutocompleteState<any>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ type QueueItem = QueueItemMap[keyof QueueItemMap];

export type InsightsClient = _InsightsClient & {
queue?: QueueItem[];
version?: string;
};

0 comments on commit c8fdd1f

Please sign in to comment.