-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide autocomplete-related data for location search (#2177)
* refactor: rename SearchResult to Place * feat: return both suggestion text and place id if available * feat: get location by ID * refactor: get rid of single-call pipelines * feat: useLocationSearchResultById hook * feat: functionality for manipulating location search suggestions * feat: fetchLocationSearchSuggestions function * feat: useLocationSearchSuggestions hook * chore: fix typos
- Loading branch information
Showing
19 changed files
with
540 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { useEffect, useState } from "react" | ||
import { fetchLocationSearchResultById } from "../api" | ||
import { LocationSearchResult } from "../models/locationSearchResult" | ||
|
||
export const useLocationSearchResultById = ( | ||
placeId: string | null | ||
): LocationSearchResult | null => { | ||
const [searchResult, setSearchResult] = useState<LocationSearchResult | null>( | ||
null | ||
) | ||
|
||
useEffect(() => { | ||
let shouldUpdate = true | ||
|
||
if (placeId) { | ||
fetchLocationSearchResultById(placeId).then((results) => { | ||
if (shouldUpdate) { | ||
setSearchResult(results) | ||
} | ||
}) | ||
} else { | ||
setSearchResult(null) | ||
} | ||
|
||
return () => { | ||
shouldUpdate = false | ||
} | ||
}, [placeId]) | ||
|
||
return searchResult | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { useEffect, useState } from "react" | ||
import { fetchLocationSearchSuggestions } from "../api" | ||
import { LocationSearchSuggestion } from "../models/locationSearchSuggestion" | ||
|
||
export const useLocationSearchSuggestions = ( | ||
text: string | null | ||
): LocationSearchSuggestion[] | null => { | ||
const [searchSuggestions, setSearchSuggestions] = useState< | ||
LocationSearchSuggestion[] | null | ||
>(null) | ||
|
||
useEffect(() => { | ||
let shouldUpdate = true | ||
|
||
if (text) { | ||
fetchLocationSearchSuggestions(text).then((results) => { | ||
if (shouldUpdate) { | ||
setSearchSuggestions(results) | ||
} | ||
}) | ||
} else { | ||
setSearchSuggestions(null) | ||
} | ||
|
||
return () => { | ||
shouldUpdate = false | ||
} | ||
}, [text]) | ||
|
||
return searchSuggestions | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export interface LocationSearchSuggestion { | ||
text: string | ||
placeId: string | null | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { Infer, nullable, string, type } from "superstruct" | ||
import { LocationSearchSuggestion } from "./locationSearchSuggestion" | ||
|
||
export const LocationSearchSuggestionData = type({ | ||
text: string(), | ||
place_id: nullable(string()), | ||
}) | ||
export type LocationSearchSuggestionData = Infer< | ||
typeof LocationSearchSuggestionData | ||
> | ||
|
||
export const locationSearchSuggestionFromData = ({ | ||
text, | ||
place_id, | ||
}: LocationSearchSuggestionData): LocationSearchSuggestion => ({ | ||
text, | ||
placeId: place_id, | ||
}) | ||
|
||
export const locationSearchSuggestionsFromData = ( | ||
locationSearchSuggestionsData: LocationSearchSuggestionData[] | ||
): LocationSearchSuggestion[] => | ||
locationSearchSuggestionsData.map(locationSearchSuggestionFromData) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { Factory } from "fishery" | ||
import { LocationSearchSuggestion } from "../../src/models/locationSearchSuggestion" | ||
|
||
const locationSearchSuggestionFactory = | ||
Factory.define<LocationSearchSuggestion>(({ sequence }) => ({ | ||
text: "Some Search Term", | ||
placeId: `${sequence}`, | ||
})) | ||
|
||
export default locationSearchSuggestionFactory |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { Factory } from "fishery" | ||
import { LocationSearchSuggestionData } from "../../src/models/locationSearchSuggestionData" | ||
|
||
const locationSearchSuggestionDataFactory = | ||
Factory.define<LocationSearchSuggestionData>(({ sequence }) => ({ | ||
text: "Some Search Term", | ||
place_id: `${sequence}`, | ||
})) | ||
|
||
export default locationSearchSuggestionDataFactory |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { useLocationSearchResultById } from "../../src/hooks/useLocationSearchResultById" | ||
import { renderHook } from "@testing-library/react" | ||
import * as Api from "../../src/api" | ||
import { instantPromise } from "../testHelpers/mockHelpers" | ||
import locationSearchResultFactory from "../factories/locationSearchResult" | ||
|
||
jest.mock("../../src/api", () => ({ | ||
__esModule: true, | ||
|
||
fetchLocationSearchResultById: jest.fn(() => new Promise(() => {})), | ||
})) | ||
|
||
describe("useLocationSearchResultById", () => { | ||
test("returns null if no search query is given", () => { | ||
const mockFetchLocationSearchResultById: jest.Mock = | ||
Api.fetchLocationSearchResultById as jest.Mock | ||
|
||
const { result } = renderHook(() => useLocationSearchResultById(null)) | ||
|
||
expect(result.current).toBeNull() | ||
expect(mockFetchLocationSearchResultById).not.toHaveBeenCalled() | ||
}) | ||
|
||
test("returns null while loading", () => { | ||
const mockFetchLocationSearchResultById: jest.Mock = | ||
Api.fetchLocationSearchResultById as jest.Mock | ||
|
||
const { result } = renderHook(() => useLocationSearchResultById("place_id")) | ||
|
||
expect(result.current).toBeNull() | ||
expect(mockFetchLocationSearchResultById).toHaveBeenCalled() | ||
}) | ||
|
||
test("returns results", () => { | ||
const results = [locationSearchResultFactory.build()] | ||
const mockFetchLocationSearchResultById: jest.Mock = | ||
Api.fetchLocationSearchResultById as jest.Mock | ||
mockFetchLocationSearchResultById.mockImplementationOnce(() => | ||
instantPromise(results) | ||
) | ||
|
||
const { result } = renderHook(() => useLocationSearchResultById("place_id")) | ||
|
||
expect(result.current).toEqual(results) | ||
expect(mockFetchLocationSearchResultById).toHaveBeenCalled() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { useLocationSearchSuggestions } from "../../src/hooks/useLocationSearchSuggestions" | ||
import { renderHook } from "@testing-library/react" | ||
import * as Api from "../../src/api" | ||
import { instantPromise } from "../testHelpers/mockHelpers" | ||
import locationSearchSuggestionFactory from "../factories/locationSearchSuggestion" | ||
|
||
jest.mock("../../src/api", () => ({ | ||
__esModule: true, | ||
|
||
fetchLocationSearchSuggestions: jest.fn(() => new Promise(() => {})), | ||
})) | ||
|
||
describe("useLocationSearchSuggestions", () => { | ||
test("returns null if no search query is given", () => { | ||
const mockFetchLocationSearchSuggestions: jest.Mock = | ||
Api.fetchLocationSearchSuggestions as jest.Mock | ||
|
||
const { result } = renderHook(() => useLocationSearchSuggestions(null)) | ||
|
||
expect(result.current).toBeNull() | ||
expect(mockFetchLocationSearchSuggestions).not.toHaveBeenCalled() | ||
}) | ||
|
||
test("returns null while loading", () => { | ||
const mockFetchLocationSearchSuggestions: jest.Mock = | ||
Api.fetchLocationSearchSuggestions as jest.Mock | ||
|
||
const { result } = renderHook(() => | ||
useLocationSearchSuggestions("search string") | ||
) | ||
|
||
expect(result.current).toBeNull() | ||
expect(mockFetchLocationSearchSuggestions).toHaveBeenCalled() | ||
}) | ||
|
||
test("returns results", () => { | ||
const results = [locationSearchSuggestionFactory.build()] | ||
const mockFetchLocationSearchSuggestions: jest.Mock = | ||
Api.fetchLocationSearchSuggestions as jest.Mock | ||
mockFetchLocationSearchSuggestions.mockImplementationOnce(() => | ||
instantPromise(results) | ||
) | ||
|
||
const { result } = renderHook(() => | ||
useLocationSearchSuggestions("search string") | ||
) | ||
|
||
expect(result.current).toEqual(results) | ||
expect(mockFetchLocationSearchSuggestions).toHaveBeenCalled() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { | ||
locationSearchSuggestionFromData, | ||
locationSearchSuggestionsFromData, | ||
} from "../../src/models/locationSearchSuggestionData" | ||
import locationSearchSuggestionFactory from "../factories/locationSearchSuggestion" | ||
import locationSearchSuggestionDataFactory from "../factories/locationSearchSuggestionData" | ||
|
||
describe("locationSearchSuggestionFromData", () => { | ||
test("passes supplied data through", () => { | ||
const data = locationSearchSuggestionDataFactory.build({ | ||
text: "Some Landmark", | ||
place_id: "test-id", | ||
}) | ||
|
||
expect(locationSearchSuggestionFromData(data)).toEqual( | ||
locationSearchSuggestionFactory.build({ | ||
text: "Some Landmark", | ||
placeId: "test-id", | ||
}) | ||
) | ||
}) | ||
}) | ||
|
||
describe("locationSearchSuggestionsFromData", () => { | ||
test("passes supplied data through", () => { | ||
const data = [ | ||
locationSearchSuggestionDataFactory.build({ | ||
text: "Some Landmark", | ||
place_id: "test-id", | ||
}), | ||
] | ||
|
||
expect(locationSearchSuggestionsFromData(data)).toEqual([ | ||
locationSearchSuggestionFactory.build({ | ||
text: "Some Landmark", | ||
placeId: "test-id", | ||
}), | ||
]) | ||
}) | ||
}) |
Oops, something went wrong.