diff --git a/.changeset/long-dryers-itch.md b/.changeset/long-dryers-itch.md
new file mode 100644
index 0000000..8d61aad
--- /dev/null
+++ b/.changeset/long-dryers-itch.md
@@ -0,0 +1,5 @@
+---
+"react-loqate": minor
+---
+
+Implement Bias and Origin parameters for use with capture v4 key
diff --git a/README.md b/README.md
index ed4d662..d99a3fa 100644
--- a/README.md
+++ b/README.md
@@ -32,17 +32,19 @@ import 'react-loqate/dist/index.css';
### Props
-| name | type | required | example | description |
-| ---------- | ----------------------------------------------------- | -------- | ------------------------------------------------------------------- | ---------------------------------------- |
-| apiKey | string | yes | "AA11-AA11-AA11-AA11" | Loqate API key |
-| locale | string | yes | "en-GB" | Language to be used |
-| onSelect | (address) => void | yes | address => console.log(address) | Callback with for Loqate response |
-| countries | string[] | no | ["GB", "NL"] | Countries to search in |
-| limit | number | no | 10 | Number of options to show |
-| classes | `{ input?: string, list?: string, listItem?: string}` | no | { list: 'list' } | Classnames for the components |
-| components | see [Customization](#Customization) | no | { Input: CustomInput, List: CustomList, ListItem: CustomListItem, } | Components to overwrite the default ones |
-| inline | boolean | no | true | Render results inline with the input |
-| debounce | number | no | 100 | Debounce the calls to the Loqate API |
+| name | type | required | example | description |
+| ---------- | ----------------------------------------------------- | -------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
+| apiKey | string | yes | "AA11-AA11-AA11-AA11" | Loqate API key |
+| locale | string | yes | "en-GB" | Language to be used |
+| onSelect | (address) => void | yes | address => console.log(address) | Callback with for Loqate response |
+| countries | string[] | no | ["GB", "NL"] | Countries to search in |
+| limit | number | no | 10 | Number of options to show |
+| classes | `{ input?: string, list?: string, listItem?: string}` | no | { list: 'list' } | Classnames for the components |
+| components | see [Customization](#Customization) | no | { Input: CustomInput, List: CustomList, ListItem: CustomListItem, } | Components to overwrite the default ones |
+| inline | boolean | no | true | Render results inline with the input |
+| debounce | number | no | 100 | Debounce the calls to the Loqate API |
+| bias | boolean | no | true | Bias feature when using capture v4 enabled key.
Requires origin to be set. |
+| origin | string | no | "93.184.216.34" | Name or ISO 2 or 3 character code of a country, WGS84 coordinates (comma separated) or IP address |
### Customization
diff --git a/src/__tests__/serverHandlers.ts b/src/__tests__/serverHandlers.ts
index d50199b..b705dd0 100644
--- a/src/__tests__/serverHandlers.ts
+++ b/src/__tests__/serverHandlers.ts
@@ -65,3 +65,24 @@ export const errorHandler = http.get(
});
}
);
+
+export const biasHandler = http.get(
+ `${LOQATE_BASE_URL}/${LOQATE_FIND_URL}`,
+ ({ request }) => {
+ const url = new URL(request.url);
+ const bias = url.searchParams.get('Bias');
+ const origin = url.searchParams.get('Origin');
+ if (bias === 'true' && origin !== '') {
+ return HttpResponse.json({
+ Items: {
+ Id: 'GB|RM|ENG|TAMWORTH-PICCADILLY',
+ Type: 'Locality',
+ Text: 'Piccadilly, Tamworth, B78',
+ Highlight: '0-10',
+ Description: '174 Addresses',
+ },
+ });
+ }
+ throw new Error(`no bias`);
+ }
+);
diff --git a/src/index.test.tsx b/src/index.test.tsx
index 90b94f4..640c616 100644
--- a/src/index.test.tsx
+++ b/src/index.test.tsx
@@ -8,6 +8,7 @@ import { selection } from './__tests__/__fixtures__/selection';
import { server } from './__tests__/server';
import { errorHandler } from './__tests__/serverHandlers';
import AddressSearch from './index';
+import Loqate from './utils/Loqate';
global.fetch = fetch;
@@ -346,3 +347,33 @@ it('lets its errors be caught by an ErrorBoundary', async () => {
expect(baseElement).toMatchSnapshot();
});
+
+it('accepts origin and bias options', async () => {
+ const findSpy = vi.spyOn(Loqate.prototype, 'find');
+
+ render(
+
+ );
+
+ const input = screen.getByRole('textbox');
+ input.focus();
+ fireEvent.change(input, { target: { value: 'a' } });
+
+ expect(findSpy).toHaveBeenCalledWith({
+ bias: true,
+ containerId: undefined,
+ countries: undefined,
+ language: 'en',
+ limit: 5,
+ origin: 'GB',
+ text: 'a',
+ });
+});
diff --git a/src/index.tsx b/src/index.tsx
index 76ce821..68bc89f 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -29,6 +29,8 @@ export interface Props {
inline?: boolean;
debounce?: number;
apiUrl?: string;
+ bias?: boolean;
+ origin?: string;
}
interface Components {
@@ -129,6 +131,8 @@ function AddressSearch(props: Props): JSX.Element {
inline,
debounce,
apiUrl,
+ bias,
+ origin,
} = props;
const loqate = useMemo(() => Loqate.create(apiKey, apiUrl), [apiKey]);
@@ -148,6 +152,8 @@ function AddressSearch(props: Props): JSX.Element {
text,
containerId,
language: loqateLanguage(locale),
+ origin,
+ bias,
});
if (res.Items) {
diff --git a/src/utils/Loqate.ts b/src/utils/Loqate.ts
index 1de0070..0f3d847 100644
--- a/src/utils/Loqate.ts
+++ b/src/utils/Loqate.ts
@@ -12,6 +12,8 @@ interface FindQuery {
countries?: string[];
limit?: number;
containerId?: string;
+ origin?: string;
+ bias?: boolean;
}
type LoqateResponse = { Items?: Item[] | LoqateErrorItem[] };
@@ -43,14 +45,25 @@ class Loqate {
}
public async find(query: FindQuery): Promise {
- const { text, countries = [], containerId, language, limit } = query;
+ const {
+ text,
+ countries = [],
+ containerId,
+ language,
+ limit,
+ origin,
+ bias,
+ } = query;
const params = new URLSearchParams({
Text: text,
Countries: countries.join(','),
language,
Key: this.key,
+ Origin: origin ? origin : '',
+ Bias: bias ? 'true' : 'false',
});
+
if (containerId) {
params.set('Container', containerId);
}
diff --git a/src/utils/__tests__/Loqate.test.ts b/src/utils/__tests__/Loqate.test.ts
index 9db82b8..2b2498f 100644
--- a/src/utils/__tests__/Loqate.test.ts
+++ b/src/utils/__tests__/Loqate.test.ts
@@ -3,7 +3,7 @@ import { describe, expect, it } from 'vitest';
import { selection } from '../../__tests__/__fixtures__/selection';
import { suggestions } from '../../__tests__/__fixtures__/suggestions';
import { server } from '../../__tests__/server';
-import { errorHandler } from '../../__tests__/serverHandlers';
+import { biasHandler, errorHandler } from '../../__tests__/serverHandlers';
import Loqate from '../Loqate';
global.fetch = fetch;
@@ -41,6 +41,31 @@ describe('Loqate', () => {
expect({ Items }).toEqual(suggestions);
});
+ it('accepts bias and origin', async () => {
+ server.use(biasHandler);
+
+ const loqate = Loqate.create('some-key');
+ const { Items } = await loqate.find({
+ text: 'some-text',
+ language: 'some-language',
+ countries: ['GB', 'US'],
+ limit: 10,
+ containerId: 'some-container-id',
+ bias: true,
+ origin: '93.184.216.34',
+ });
+
+ expect({ Items }).toEqual({
+ Items: {
+ Id: 'GB|RM|ENG|TAMWORTH-PICCADILLY',
+ Type: 'Locality',
+ Text: 'Piccadilly, Tamworth, B78',
+ Highlight: '0-10',
+ Description: '174 Addresses',
+ },
+ });
+ });
+
it('should throw errors', async () => {
server.use(errorHandler);