Skip to content

Commit

Permalink
feat(getUserToken): add a way to get user token (#107)
Browse files Browse the repository at this point in the history
* feat(processQueue): introduce callback parameters for method invoker

* feat(getUserToken): allow calling with invoker

This allows to call getUserToken async.
It's useful when you want to be able to call it even when the library is
not fully loaded.

The goal for retrieving the user token is usally to add it as a header
on the searchClient. This enables Personalized results.

```ts
const searchClient = algoliasearch("APPLICATION_ID", "SEARCH_API_KEY");

// install search insights lib

aa('init', {...})
aa('getUserToken', _, (err, userToken) => {
  searchClient.setExtraHeader("X-Algolia-UserToken", userToken);
})

// search insights loads laters
```
This targets this JIRA ticket https://algolia.atlassian.net/browse/IFW-400

* fix: add comment clarifying test function in test

* fix: add typing for the queue
  • Loading branch information
tkrugg authored Apr 17, 2019
1 parent 42541c8 commit 29786e1
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 15 deletions.
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,26 @@ aa("convertedObjectIDsAfterSearch", {
### Initialize

```js
const searchClient = algoliasearch("APPLICATION_ID", "SEARCH_API_KEY");
const search = instantsearch({
appId: "APPLICATION_ID",
apiKey: "SEARCH_API_KEY",
searchClient,
indexName: "INDEX_NAME",
searchParameters: {
enablePersonalization: true
}
});
```

### Access userToken

In cases where the userToken is generated, you will need a way to access the userToken so that you can pass it to the searchClient.

```ts
aa("getUserToken", null, (err, userToken) => {
searchClient.setExtraHeader("X-Algolia-UserToken", userToken);
});
```

### Reporting a click event

```js
Expand Down
12 changes: 11 additions & 1 deletion lib/__tests__/_processQueue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class FakeAlgoliaAnalytics {
constructor() {
this.init = jest.fn();
this.otherMethod = jest.fn(() => "otherMethodReturnedValue");
this.processQueue = processQueue.bind(this);

this.processQueue = processQueue.bind(this); // the function we'll be testing
}
}

Expand Down Expand Up @@ -58,4 +59,13 @@ describe("processQueue", () => {
expect(insights.init).toHaveBeenCalledWith({ appID: "xxx", apiKey: "yyy" });
expect(insights.otherMethod).toHaveBeenCalledWith({ objectIDs: ["1"] });
});

it("should return method output in a callback", () => {
insights.processQueue(globalObject);

const callback = jest.fn();
globalObject.aa("otherMethod", { objectIDs: ["1"] }, callback);

expect(callback).toHaveBeenCalledWith(null, "otherMethodReturnedValue");
});
});
35 changes: 23 additions & 12 deletions lib/_processQueue.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,42 @@
/**
* Processes queue that might have been set before
* the script was actually loaded and reassigns
* class over window variable to execute commands
* class over globalObject variable to execute commands
* instead of putting them to the queue
* @return {[type]} [description]
*/
import { isFunction } from "./utils";

type QueueItemCallback = (err: any, res: any) => void;
type QueueItem = [string, any, QueueItemCallback?];

export function processQueue(globalObject) {
// Set pointer which allows renaming of the script
const pointer = globalObject["AlgoliaAnalyticsObject"] as any;
const pointer = globalObject["AlgoliaAnalyticsObject"] as string;

// Check if there is a queue
if (pointer) {
const queue = globalObject[pointer].queue || [];
const queue: QueueItem[] = globalObject[pointer].queue || [];

// Loop queue and execute functions in the queue
queue.forEach((fn: string[]) => {
const functionName = fn[0];
const functionArguments = fn[1];

if (functionName && typeof (this as any)[functionName] === "function") {
this[functionName](functionArguments);
queue.forEach(([functionName, functionArguments, functionCallback]) => {
if (functionName && isFunction((this as any)[functionName])) {
const output: any = this[functionName](functionArguments);
if (isFunction(functionCallback)) {
functionCallback(null, output);
}
}
});

// Reassign pointer
globalObject[pointer] = (functionName: string, functionArguments: string) => {
(this as any)[functionName](functionArguments);
globalObject[pointer] = (
functionName: string,
functionArguments: any,
functionCallback: QueueItemCallback
) => {
const output = (this as any)[functionName](functionArguments);
if (isFunction(functionCallback)) {
functionCallback(null, output);
}
};
}
}

0 comments on commit 29786e1

Please sign in to comment.