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);