diff --git a/package-lock.json b/package-lock.json index dfdf6fd28836..e2ff69cad626 100644 --- a/package-lock.json +++ b/package-lock.json @@ -107,7 +107,7 @@ "react-native-fs": "^2.20.0", "react-native-gesture-handler": "2.28.0", "react-native-get-random-values": "^1.11.0", - "react-native-google-places-autocomplete": "2.5.6", + "react-native-google-places-autocomplete": "2.6.4", "react-native-haptic-feedback": "^2.3.3", "react-native-image-picker": "^7.1.2", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#8a1c3b7359977462cdd4e63b09ea45afbd3d77c7", @@ -33859,20 +33859,27 @@ } }, "node_modules/react-native-google-places-autocomplete": { - "version": "2.5.6", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/react-native-google-places-autocomplete/-/react-native-google-places-autocomplete-2.6.4.tgz", + "integrity": "sha512-/DjXEa20doSJYiykqLbTAPL3GtIHVRdjpAoPpxnLXK6uFi103wdqXZoqXnKdqlov/lJLIO8Wex6GIu6MZz3Osw==", "license": "MIT", "dependencies": { "lodash.debounce": "^4.0.8", - "prop-types": "^15.7.2", - "qs": "~6.9.1" + "qs": "^6.14.1", + "react-native-uuid": "^2.0.3" }, "peerDependencies": { "react-native": ">= 0.59" } }, "node_modules/react-native-google-places-autocomplete/node_modules/qs": { - "version": "6.9.7", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, "engines": { "node": ">=0.6" }, @@ -34534,6 +34541,16 @@ "react-native": "*" } }, + "node_modules/react-native-uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.3.tgz", + "integrity": "sha512-f/YfIS2f5UB+gut7t/9BKGSCYbRA9/74A5R1MDp+FLYsuS+OSWoiM/D8Jko6OJB6Jcu3v6ONuddvZKHdIGpeiw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0", + "npm": ">=6.0.0" + } + }, "node_modules/react-native-view-shot": { "version": "4.0.0", "license": "MIT", diff --git a/package.json b/package.json index 73067434d827..26f5ac830707 100644 --- a/package.json +++ b/package.json @@ -170,7 +170,7 @@ "react-native-fs": "^2.20.0", "react-native-gesture-handler": "2.28.0", "react-native-get-random-values": "^1.11.0", - "react-native-google-places-autocomplete": "2.5.6", + "react-native-google-places-autocomplete": "2.6.4", "react-native-haptic-feedback": "^2.3.3", "react-native-image-picker": "^7.1.2", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#8a1c3b7359977462cdd4e63b09ea45afbd3d77c7", diff --git a/patches/react-native-google-places-autocomplete/details.md b/patches/react-native-google-places-autocomplete/details.md index 3e6c08def754..9472b3b05f5a 100644 --- a/patches/react-native-google-places-autocomplete/details.md +++ b/patches/react-native-google-places-autocomplete/details.md @@ -1,13 +1,112 @@ # `react-native-google-places-autocomplete` patches -### [react-native-google-places-autocomplete+2.5.6+001+react-19-support.patch](react-native-google-places-autocomplete+2.5.6+001+react-19-support.patch) +### [react-native-google-places-autocomplete+2.6.4+001+fix-tdz-crash.patch](react-native-google-places-autocomplete+2.6.4+001+fix-tdz-crash.patch) - Reason: - + ``` - This patch supports for React 19 by removing propTypes. + Fixes TDZ crashes and reorders forward-referenced declarations in v2.6.4: + + 1. `useRef(_request)` on line 161 references `_request` before its `const` + declaration on line 466, causing + `ReferenceError: Cannot access '_request' before initialization`. + Fix: replace the initial value with `null` (safe because + `requestRef.current` is reassigned to `_request` every render before + it can be invoked). + + 2. `_disableRowLoaders` (a `const useCallback`) was declared on line 653 + but referenced in the `useCallback` dependency arrays of + `_requestNearby` (line 450) and `getCurrentLocation` (line 629), + causing `ReferenceError: Cannot access '_disableRowLoaders' before + initialization`. Fix: move `_disableRowLoaders` above + `_requestNearby` so it is defined before first use. + + 3. Several functions were declared after their callers, creating forward + references. While these only execute lazily (not during render), they + are reordered for clarity and consistency: + - `_renderDescription`, `hideListView`, `isNewFocusInAutocompleteResultList`, + `_onBlur`, `_onFocus` moved before `_onPress` (which calls them). + - `debounceData` moved before `_onChangeText` (which calls it). + + 4. v2.6.4 added `hideListView(true)` at the start of `_onPress` in the + `fetchDetails` branch. This immediately hides the entire FlatList + before `_enableRowLoader` can display the per-row loading spinner, + causing the loading indicator to be invisible during place detail + fetches. Fix: remove `hideListView(true)` from the `fetchDetails` + branch of `_onPress`, restoring v2.5.6 behavior where the list + stays visible with the row spinner until the detail request completes. + The `hideListView(true)` calls in the `isCurrentLocation` and + predefined-place branches are left intact since those don't need + to show a row-level loading indicator. + + 5. v2.6.4 changed the `_getFlatList` visibility condition from + `stateText !== ''` (v2.5.6) to `dataSource.length > 0`. This + prevents the FlatList from mounting when the user is typing but + results haven't arrived yet, so the `ListEmptyComponent` loading + spinner is never shown during in-flight requests. Fix: replace + `dataSource.length > 0` with the v2.5.6-style condition + `(stateText !== '' || predefinedPlaces.length > 0 || currentLocation === true)` + so the FlatList renders while results are loading. This matches + v2.5.6 production behavior where existing results stay visible + while new results load — `_request` does NOT clear `dataSource` + before sending the XHR, so previous results remain visible until + the new response arrives. + + 6. v2.6.4 added `stateText` to the dependency array of the + query-change `useEffect` (the effect that reloads search when + `props.query` changes). This causes the cleanup function + (`_abortRequests`) to fire on every keystroke, aborting in-flight + XHRs before results can arrive. When the user types fast, results + from previous keystrokes never complete, `dataSource` stays empty, + and the `ListEmptyComponent` loading spinner flashes on every key. + Fix: remove `stateText` from the dependency array. Per-keystroke + requests are already handled by `_onChangeText` → `debounceData`, + and `_request` itself calls `_abortRequests()` at the top, so old + requests are properly aborted when a new one fires. + + 7. In v2.6.4, `requestsRef` is a `useRef` that persists across renders + (unlike v2.5.6 where `_requests` was a plain `let` re-initialized + every render). This means `_abortRequests()` inside `_request` now + actually aborts the previous in-flight XHR. When the user types + faster than the API responds, each keystroke aborts the prior XHR + before it populates `dataSource`, keeping `dataSource` empty and + causing `ListEmptyComponent` to show the loading spinner on every + keystroke. Fix: only call `setListLoaderDisplayed(true)` in the + `onreadystatechange` handler when `resultsRef.current.length === 0` + (i.e., no prior results exist). When prior results already exist + they remain visible in the FlatList while the new request is + in-flight, matching v2.5.6 production behavior. Applied to both + `_request` and `_requestNearby`. + + 8. When `resultsRef.current.length === 0` and the loading spinner is + enabled, `dataSource` may still contain predefined places (populated + by `buildRowsFromResults([])` when the user cleared the input). + Since `ListEmptyComponent` only renders when `data` is empty, + the loading spinner was invisible even though `listLoaderDisplayed` + was true. Fix: call `setDataSource([])` alongside + `setListLoaderDisplayed(true)` to clear stale predefined places + from the FlatList data, allowing `ListEmptyComponent` to render + the loading spinner. Applied to both `_request` and + `_requestNearby`. + + 9. v2.6.4 replaced `TouchableHighlight` with `Pressable` for suggestion + rows AND added `onBlur={_onBlur}` to the Pressable. This causes two + problems on iOS: + (a) `Pressable` does not participate in the gesture responder system + the same way `TouchableHighlight` does. When a parent `ScrollView` + uses `keyboardShouldPersistTaps="handled"` (as `FormWrapper` does), + `TouchableHighlight` counts as "handling" the tap so the keyboard + stays up and `onPress` fires. `Pressable` does not, so the first + tap dismisses the keyboard without firing `onPress`, making + suggestion selection appear broken. + (b) The `onBlur={_onBlur}` on the Pressable fires when the keyboard + dismisses, calling `hideListView()` and `inputRef.current.blur()`, + which cascades to AddressSearch collapsing the list to zero height. + Fix: replace `Pressable` with `TouchableHighlight` (restoring v2.5.6 + behavior) and remove the `onBlur` handler. `TouchableHighlight` uses + `underlayColor` for press feedback instead of function-style styles. ``` - -- Upstream PR/issue: https://github.com/FaridSafi/react-native-google-places-autocomplete/pull/970 -- E/App issue: https://github.com/Expensify/App/issues/57511 -- PR introducing patch: https://github.com/Expensify/App/pull/60421 \ No newline at end of file + +- Upstream PR/issue: 🛑, library is unmaintained (https://github.com/FaridSafi/react-native-google-places-autocomplete/issues/978) +- E/App issue: https://github.com/Expensify/App/pull/82233 +- PR introducing patch: https://github.com/Expensify/App/pull/82233 diff --git a/patches/react-native-google-places-autocomplete/react-native-google-places-autocomplete+2.5.6+001+react-19-support.patch b/patches/react-native-google-places-autocomplete/react-native-google-places-autocomplete+2.5.6+001+react-19-support.patch deleted file mode 100644 index 0c72fb0dac68..000000000000 --- a/patches/react-native-google-places-autocomplete/react-native-google-places-autocomplete+2.5.6+001+react-19-support.patch +++ /dev/null @@ -1,122 +0,0 @@ -diff --git a/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js b/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js -index 99a2a13..f733e49 100644 ---- a/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js -+++ b/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js -@@ -70,7 +70,56 @@ const defaultStyles = { - powered: {}, - }; - --export const GooglePlacesAutocomplete = forwardRef((props, ref) => { -+const defaultProps = { -+ autoFillOnNotFound: false, -+ currentLocation: false, -+ currentLocationLabel: 'Current location', -+ debounce: 0, -+ disableScroll: false, -+ enableHighAccuracyLocation: true, -+ enablePoweredByContainer: true, -+ fetchDetails: false, -+ filterReverseGeocodingByTypes: [], -+ GooglePlacesDetailsQuery: {}, -+ GooglePlacesSearchQuery: { -+ rankby: 'distance', -+ type: 'restaurant', -+ }, -+ GoogleReverseGeocodingQuery: {}, -+ isRowScrollable: true, -+ keyboardShouldPersistTaps: 'always', -+ listHoverColor: '#ececec', -+ listUnderlayColor: '#c8c7cc', -+ listViewDisplayed: 'auto', -+ keepResultsAfterBlur: false, -+ minLength: 0, -+ nearbyPlacesAPI: 'GooglePlacesSearch', -+ numberOfLines: 1, -+ onFail: () => {}, -+ onNotFound: () => {}, -+ onPress: () => {}, -+ onTimeout: () => console.warn('google places autocomplete: request timeout'), -+ placeholder: '', -+ predefinedPlaces: [], -+ predefinedPlacesAlwaysVisible: false, -+ query: { -+ key: 'missing api key', -+ language: 'en', -+ types: 'geocode', -+ }, -+ styles: {}, -+ suppressDefaultStyles: false, -+ textInputHide: false, -+ textInputProps: {}, -+ timeout: 20000, -+}; -+ -+export const GooglePlacesAutocomplete = ({ ref, ...rest }) => { -+ const props = { -+ ...defaultProps, -+ ...rest, -+ }; -+ - let _results = []; - let _requests = []; - -@@ -887,7 +936,7 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { - {props.children} - - ); --}); -+}; - - GooglePlacesAutocomplete.propTypes = { - autoFillOnNotFound: PropTypes.bool, -@@ -944,50 +993,6 @@ GooglePlacesAutocomplete.propTypes = { - timeout: PropTypes.number, - }; - --GooglePlacesAutocomplete.defaultProps = { -- autoFillOnNotFound: false, -- currentLocation: false, -- currentLocationLabel: 'Current location', -- debounce: 0, -- disableScroll: false, -- enableHighAccuracyLocation: true, -- enablePoweredByContainer: true, -- fetchDetails: false, -- filterReverseGeocodingByTypes: [], -- GooglePlacesDetailsQuery: {}, -- GooglePlacesSearchQuery: { -- rankby: 'distance', -- type: 'restaurant', -- }, -- GoogleReverseGeocodingQuery: {}, -- isRowScrollable: true, -- keyboardShouldPersistTaps: 'always', -- listHoverColor: '#ececec', -- listUnderlayColor: '#c8c7cc', -- listViewDisplayed: 'auto', -- keepResultsAfterBlur: false, -- minLength: 0, -- nearbyPlacesAPI: 'GooglePlacesSearch', -- numberOfLines: 1, -- onFail: () => {}, -- onNotFound: () => {}, -- onPress: () => {}, -- onTimeout: () => console.warn('google places autocomplete: request timeout'), -- placeholder: '', -- predefinedPlaces: [], -- predefinedPlacesAlwaysVisible: false, -- query: { -- key: 'missing api key', -- language: 'en', -- types: 'geocode', -- }, -- styles: {}, -- suppressDefaultStyles: false, -- textInputHide: false, -- textInputProps: {}, -- timeout: 20000, --}; -- - GooglePlacesAutocomplete.displayName = 'GooglePlacesAutocomplete'; - - export default { GooglePlacesAutocomplete }; diff --git a/patches/react-native-google-places-autocomplete/react-native-google-places-autocomplete+2.6.4+001+fix-tdz-crash.patch b/patches/react-native-google-places-autocomplete/react-native-google-places-autocomplete+2.6.4+001+fix-tdz-crash.patch new file mode 100644 index 000000000000..3b28eb374cf5 --- /dev/null +++ b/patches/react-native-google-places-autocomplete/react-native-google-places-autocomplete+2.6.4+001+fix-tdz-crash.patch @@ -0,0 +1,302 @@ +diff --git a/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js b/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js +index 9fedd7e..258a17a 100644 +--- a/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js ++++ b/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js +@@ -17,11 +17,11 @@ import { + Image, + Keyboard, + Platform, +- Pressable, + ScrollView, + StyleSheet, + Text, + TextInput, ++ TouchableHighlight, + View, + } from 'react-native'; + +@@ -158,7 +158,7 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + const prevQueryStringRef = useRef(JSON.stringify(query)); + + // Store latest _request function - ensures debounced function always calls current version with latest closures +- const requestRef = useRef(_request); ++ const requestRef = useRef(null); + const queryString = useMemo(() => JSON.stringify(query), [query]); + + const [stateText, setStateText] = useState(''); +@@ -347,6 +347,16 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + return rowData; + }; + ++ const _disableRowLoaders = useCallback(() => { ++ for (let i = 0; i < resultsRef.current.length; i++) { ++ if (resultsRef.current[i].isLoading === true) { ++ resultsRef.current[i].isLoading = false; ++ } ++ } ++ ++ setDataSource(buildRowsFromResults(resultsRef.current)); ++ }, [buildRowsFromResults]); ++ + // ========================================================================== + // API REQUEST FUNCTIONS + // ========================================================================== +@@ -367,7 +377,13 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + request.ontimeout = onTimeout; + request.onreadystatechange = () => { + if (request.readyState !== 4) { +- setListLoaderDisplayed(true); ++ // Only show the loading spinner when there are no prior results. ++ if (resultsRef.current.length === 0) { ++ setListLoaderDisplayed(true); ++ // Clear dataSource so FlatList's ListEmptyComponent can render ++ // the loading spinner (it only renders when data is empty). ++ setDataSource([]); ++ } + return; + } + +@@ -478,7 +494,15 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + request.ontimeout = onTimeout; + request.onreadystatechange = () => { + if (request.readyState !== 4) { +- setListLoaderDisplayed(true); ++ // Only show the loading spinner when there are no prior results. ++ // When prior results exist they stay visible while the new request ++ // is in-flight, matching v2.5.6 production behavior. ++ if (resultsRef.current.length === 0) { ++ setListLoaderDisplayed(true); ++ // Clear dataSource so FlatList's ListEmptyComponent can render ++ // the loading spinner (it only renders when data is empty). ++ setDataSource([]); ++ } + return; + } + +@@ -650,15 +674,51 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + } + }; + +- const _disableRowLoaders = useCallback(() => { +- for (let i = 0; i < resultsRef.current.length; i++) { +- if (resultsRef.current[i].isLoading === true) { +- resultsRef.current[i].isLoading = false; ++ const _renderDescription = (rowData) => { ++ if (props.renderDescription) { ++ return props.renderDescription(rowData); ++ } ++ ++ return rowData.description || rowData.formatted_address || rowData.name; ++ }; ++ ++ const hideListView = useCallback( ++ (force = false) => { ++ if (!keepResultsAfterBlur || force) { ++ setListWasDismissed(true); ++ setListViewDisplayed(false); + } ++ }, ++ [keepResultsAfterBlur], ++ ); ++ ++ const isNewFocusInAutocompleteResultList = ({ ++ relatedTarget, ++ currentTarget, ++ }) => { ++ if (!relatedTarget) return false; ++ ++ let node = relatedTarget.parentNode; ++ ++ while (node) { ++ if (node.id === 'result-list-id') return true; ++ node = node.parentNode; + } + +- setDataSource(buildRowsFromResults(resultsRef.current)); +- }, [buildRowsFromResults]); ++ return false; ++ }; ++ ++ const _onBlur = (e) => { ++ if (e && isNewFocusInAutocompleteResultList(e)) return; ++ ++ hideListView(); ++ inputRef?.current?.blur(); ++ }; ++ ++ const _onFocus = () => { ++ setListWasDismissed(false); ++ setListViewDisplayed(true); ++ }; + + const _onPress = (rowData) => { + if (rowData.isPredefinedPlace !== true && fetchDetails === true) { +@@ -667,7 +727,6 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + return; + } + +- hideListView(true); + Keyboard.dismiss(); + + _abortRequests(); +@@ -776,7 +835,21 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + } + }; + ++ // Debounce setup ++ const debounceData = useMemo(() => { ++ return debounce((text) => requestRef.current(text), debounceMs); ++ }, [debounceMs]); ++ + const _onChangeText = (text) => { ++ // When the search text is cleared, immediately clear stale results so ++ // that the next search shows the loading spinner. We cannot rely on ++ // _request("") via debounce because a fast follow-up keystroke cancels ++ // the pending debounce call. ++ if (!text) { ++ resultsRef.current = []; ++ setDataSource(buildRowsFromResults([])); ++ } ++ + setListWasDismissed(false); + setStateText(text); + debounceData(text); +@@ -792,56 +865,10 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + } + }; + +- const hideListView = useCallback( +- (force = false) => { +- if (!keepResultsAfterBlur || force) { +- setListWasDismissed(true); +- setListViewDisplayed(false); +- } +- }, +- [keepResultsAfterBlur], +- ); +- +- const isNewFocusInAutocompleteResultList = ({ +- relatedTarget, +- currentTarget, +- }) => { +- if (!relatedTarget) return false; +- +- let node = relatedTarget.parentNode; +- +- while (node) { +- if (node.id === 'result-list-id') return true; +- node = node.parentNode; +- } +- +- return false; +- }; +- +- const _onBlur = (e) => { +- if (e && isNewFocusInAutocompleteResultList(e)) return; +- +- hideListView(); +- inputRef?.current?.blur(); +- }; +- +- const _onFocus = () => { +- setListWasDismissed(false); +- setListViewDisplayed(true); +- }; +- + // ========================================================================== + // RENDER FUNCTIONS + // ========================================================================== + +- const _renderDescription = (rowData) => { +- if (props.renderDescription) { +- return props.renderDescription(rowData); +- } +- +- return rowData.description || rowData.formatted_address || rowData.name; +- }; +- + const _getRowLoader = () => { + return ; + }; +@@ -894,19 +921,12 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + showsHorizontalScrollIndicator={false} + showsVerticalScrollIndicator={false} + > +- [ ++ _onPress(rowData)} +- onBlur={_onBlur} ++ underlayColor={listUnderlayColor} + > + { + {_renderLoader(rowData)} + {_renderRowData(rowData, index)} + +- ++ + + ); + }; +@@ -1010,15 +1030,17 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + return `item_${index}`; + }; + +- // Show list if: +- // 1. Platform is supported +- // 2. There's data to show (dataSource has items) +- // 3. listViewDisplayed is true OR we're in 'auto' mode (auto-shows when data exists) ++ // Show list when the user is actively searching, has predefined places, or ++ // uses current location. We check stateText instead of dataSource.length so ++ // that the FlatList mounts while results are still loading — this lets ++ // ListEmptyComponent render the loading spinner. + const isAutoMode = + listViewDisplayedProp === 'auto' || listViewDisplayedProp === undefined; + const shouldShowList = + supportedPlatform() && +- dataSource.length > 0 && ++ (stateText !== '' || ++ predefinedPlaces.length > 0 || ++ currentLocation === true) && + (listViewDisplayed === true || (isAutoMode && !listWasDismissed)); + + if (shouldShowList) { +@@ -1078,11 +1100,6 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + // Keep requestRef updated + requestRef.current = _request; + +- // Debounce setup +- const debounceData = useMemo(() => { +- return debounce((text) => requestRef.current(text), debounceMs); +- }, [debounceMs]); +- + useEffect(() => { + return () => { + // Cleanup debounced function on unmount +@@ -1106,7 +1123,13 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { + return () => { + _abortRequests(); + }; +- }, [queryString, debounceData, stateText, minLength, _abortRequests]); ++ // Note: stateText is intentionally excluded — per-keystroke requests are ++ // handled by _onChangeText → debounceData. Including stateText here ++ // causes the cleanup (_abortRequests) to fire on every keystroke, aborting ++ // in-flight XHRs before results arrive and making the loading spinner ++ // flash repeatedly. ++ // eslint-disable-next-line react-hooks/exhaustive-deps ++ }, [queryString, debounceData, minLength, _abortRequests]); + + // Auto-show list when dataSource has items in 'auto' mode + useEffect(() => { diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index ff8bf9746bfe..3e5be6ec98bc 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -447,6 +447,7 @@ function AddressSearch({ description: [styles.googleSearchText], separator: [styles.googleSearchSeparator, styles.overflowAuto], container: [styles.mh100], + loader: [styles.dNone], }} numberOfLines={2} isRowScrollable={false} diff --git a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx index 1a4558966668..5fed55b7c851 100644 --- a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx +++ b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx @@ -4,6 +4,7 @@ import type {TextInput} from 'react-native'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import AddressSearch from '@components/AddressSearch'; +import type {PredefinedPlace} from '@components/AddressSearch/types'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import Button from '@components/Button'; import FormProvider from '@components/Form/FormProvider'; @@ -37,7 +38,7 @@ import withWritableReportOrNotFound from './withWritableReportOrNotFound'; // Only grab the most recent 20 waypoints because that's all that is shown in the UI. This also puts them into the format of data // that the google autocomplete component expects for it's "predefined places" feature. -function recentWaypointsSelector(waypoints: RecentWaypoint[] = []) { +function recentWaypointsSelector(waypoints: RecentWaypoint[] = []): PredefinedPlace[] { return waypoints .slice(0, CONST.RECENT_WAYPOINTS_NUMBER) .filter((waypoint) => waypoint.keyForList?.includes(CONST.YOUR_LOCATION_TEXT) !== true) @@ -48,6 +49,8 @@ function recentWaypointsSelector(waypoints: RecentWaypoint[] = []) { location: { lat: waypoint.lat ?? 0, lng: waypoint.lng ?? 0, + latitude: waypoint.lat ?? 0, + longitude: waypoint.lng ?? 0, }, }, }));