Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9bf8632
Announce search suggestions and results for screen readers
MelvinBot Mar 19, 2026
8e17200
Fix: Add missing sentryLabel prop to PressableWithFeedback
MelvinBot Mar 19, 2026
569fd2d
Add missing resultsAvailable and suggestionsAvailable translation keys
MelvinBot Mar 19, 2026
59c8e7a
Use one/other plural translation objects for resultsAvailable and sug…
MelvinBot Mar 19, 2026
cfbf7c8
Fix generateTranslations check by using simple function pattern for a…
MelvinBot Mar 19, 2026
df438e6
Add missing resultsAvailable and suggestionsAvailable translations to…
MelvinBot Mar 19, 2026
4c19e20
Use one/other plural translation objects for resultsAvailable and sug…
MelvinBot Mar 19, 2026
0e599c6
Remove manual translations for resultsAvailable/suggestionsAvailable
MelvinBot Mar 19, 2026
b1e3aa3
Add missing resultsAvailable and suggestionsAvailable translation key…
MelvinBot Mar 19, 2026
f54a1d2
Merge remote-tracking branch 'origin/main' into claude-searchSuggesti…
MelvinBot Mar 19, 2026
652a6e9
Merge remote-tracking branch 'origin/main' into claude-searchSuggesti…
MelvinBot Mar 20, 2026
ed73bbd
Revert to only fix Address line 1 accessibility announcement
MelvinBot Mar 22, 2026
9207840
Fix: replace deprecated absoluteFillObject with absoluteFill
MelvinBot Mar 22, 2026
b6c0520
Update announcement to include query, revert unrelated translation ch…
MelvinBot Mar 22, 2026
668645e
Merge remote-tracking branch 'origin/main' into claude-searchSuggesti…
MelvinBot Mar 22, 2026
6285130
Fix: Suppress suggestions announcement while results are loading
MelvinBot Mar 22, 2026
200d527
Suppress suggestions announcement when list is empty
MelvinBot Mar 22, 2026
6f4fbdf
Fix: run prettier on AddressSearch component
MelvinBot Mar 22, 2026
ee0a226
Fix: skip 'for' in announcement when searchString is empty and trim s…
MelvinBot Mar 22, 2026
2add63b
Fix: apply Prettier formatting to AddressSearch
MelvinBot Mar 22, 2026
bab1342
Merge remote-tracking branch 'origin/main' into claude-searchSuggesti…
MelvinBot Mar 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 39 additions & 11 deletions src/components/AddressSearch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,18 @@ function isPlaceMatchForSearch(search: string, place: PredefinedPlace): boolean
// VirtualizedList component with a VirtualizedList-backed instead
LogBox.ignoreLogs(['VirtualizedLists should never be nested']);

function AddressSearchListEmptyComponent({searchValue}: {searchValue: string}) {
function AddressSearchListEmptyComponent({searchValue, onEmptyChange}: {searchValue: string; onEmptyChange: (isEmpty: boolean) => void}) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const noResultsFoundText = translate('common.noResultsFound');

useDebouncedAccessibilityAnnouncement(noResultsFoundText, true, searchValue);

useEffect(() => {
onEmptyChange(true);
return () => onEmptyChange(false);
}, [onEmptyChange]);

return (
<Text
style={[styles.textLabel, styles.colorMuted, styles.pv4, styles.ph3, styles.overflowAuto]}
Expand All @@ -66,6 +71,22 @@ function AddressSearchListEmptyComponent({searchValue}: {searchValue: string}) {
);
}

function AddressSearchListLoader({onLoadingChange}: {onLoadingChange: (isLoading: boolean) => void}) {
const styles = useThemeStyles();
const reasonAttributes: SkeletonSpanReasonAttributes = {context: 'AddressSearch.listLoader'};

useEffect(() => {
onLoadingChange(true);
return () => onLoadingChange(false);
}, [onLoadingChange]);

return (
<View style={[styles.pv4]}>
<ActivityIndicator reasonAttributes={reasonAttributes} />
</View>
);
}

function AddressSearch({
canUseCurrentLocation = false,
containerStyles,
Expand Down Expand Up @@ -112,9 +133,18 @@ function AddressSearch({
const [searchValue, setSearchValue] = useState('');
const [locationErrorCode, setLocationErrorCode] = useState<GeolocationErrorCodeType>(null);
const [isFetchingCurrentLocation, setIsFetchingCurrentLocation] = useState(false);
const [isLoadingResults, setIsLoadingResults] = useState(false);
const [isListEmpty, setIsListEmpty] = useState(false);
const shouldTriggerGeolocationCallbacks = useRef(true);
const [shouldHidePredefinedPlaces, setShouldHidePredefinedPlaces] = useState(false);
const containerRef = useRef<View>(null);

useDebouncedAccessibilityAnnouncement(
translate('common.suggestionsAvailableFor', searchValue.trim()),
displayListViewBorder && isTyping && !isLoadingResults && !isListEmpty,
searchValue,
);

const query = useMemo(
() => ({
language: preferredLocale,
Expand Down Expand Up @@ -345,16 +375,14 @@ function AddressSearch({
return predefinedPlaces?.filter((predefinedPlace) => isPlaceMatchForSearch(searchValue, predefinedPlace)) ?? [];
}, [predefinedPlaces, searchValue, shouldHidePredefinedPlaces]);

const listEmptyComponent = isTyping ? <AddressSearchListEmptyComponent searchValue={searchValue} /> : undefined;
const listEmptyComponent = isTyping ? (
<AddressSearchListEmptyComponent
searchValue={searchValue}
onEmptyChange={setIsListEmpty}
/>
) : undefined;

const listLoader = useMemo(() => {
const reasonAttributes: SkeletonSpanReasonAttributes = {context: 'AddressSearch.listLoader'};
return (
<View style={[styles.pv4]}>
<ActivityIndicator reasonAttributes={reasonAttributes} />
</View>
);
}, [styles.pv4]);
const listLoader = useMemo(() => <AddressSearchListLoader onLoadingChange={setIsLoadingResults} />, []);

const fetchingLocationReasonAttributes: SkeletonSpanReasonAttributes = {
context: 'AddressSearch.isFetchingCurrentLocation',
Expand Down Expand Up @@ -500,7 +528,7 @@ function AddressSearch({
</View>
</ScrollView>
{isFetchingCurrentLocation && (
<View style={[StyleSheet.absoluteFillObject, styles.fullScreenLoading, styles.w100]}>
<View style={[StyleSheet.absoluteFill, styles.fullScreenLoading, styles.w100]}>
<ActivityIndicator
size={CONST.ACTIVITY_INDICATOR_SIZE.LARGE}
reasonAttributes={fetchingLocationReasonAttributes}
Expand Down
3 changes: 2 additions & 1 deletion src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ const translations: TranslationDeepObject<typeof en> = {
send: 'Senden',
na: 'k. A.',
noResultsFound: 'Keine Ergebnisse gefunden',
noResultsFoundMatching: (searchString: string) => `Keine Ergebnisse gefunden für „${searchString}“`,
noResultsFoundMatching: (searchString: string) => `Keine Ergebnisse gefunden für „${searchString}”`,
suggestionsAvailableFor: (searchString: string) => (searchString ? `Vorschläge verfügbar für „${searchString}”.` : 'Vorschläge verfügbar.'),
recentDestinations: 'Letzte Ziele',
timePrefix: 'Es ist',
conjunctionFor: 'für',
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ const translations = {
na: 'N/A',
noResultsFound: 'No results found',
noResultsFoundMatching: (searchString: string) => `No results found matching "${searchString}"`,
suggestionsAvailableFor: (searchString: string) => (searchString ? `Suggestions available for "${searchString}".` : 'Suggestions available.'),
recentDestinations: 'Recent destinations',
timePrefix: "It's",
conjunctionFor: 'for',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ const translations: TranslationDeepObject<typeof en> = {
na: 'N/A',
noResultsFound: 'No se han encontrado resultados',
noResultsFoundMatching: (searchString: string) => `No se encontraron resultados que coincidan con "${searchString}"`,
suggestionsAvailableFor: (searchString: string) => (searchString ? `Sugerencias disponibles para "${searchString}".` : 'Sugerencias disponibles.'),
recentDestinations: 'Destinos recientes',
timePrefix: 'Son las',
conjunctionFor: 'para',
Expand Down
1 change: 1 addition & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ const translations: TranslationDeepObject<typeof en> = {
na: 'N/D',
noResultsFound: 'Aucun résultat trouvé',
noResultsFoundMatching: (searchString: string) => `Aucun résultat trouvé correspondant à « ${searchString} »`,
suggestionsAvailableFor: (searchString: string) => (searchString ? `Suggestions disponibles pour « ${searchString} ».` : 'Suggestions disponibles.'),
recentDestinations: 'Destinations récentes',
timePrefix: "C'est",
conjunctionFor: 'pour',
Expand Down
1 change: 1 addition & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ const translations: TranslationDeepObject<typeof en> = {
na: 'N/D',
noResultsFound: 'Nessun risultato trovato',
noResultsFoundMatching: (searchString: string) => `Nessun risultato trovato per "${searchString}"`,
suggestionsAvailableFor: (searchString: string) => (searchString ? `Suggerimenti disponibili per "${searchString}".` : 'Suggerimenti disponibili.'),
recentDestinations: 'Destinazioni recenti',
timePrefix: 'È',
conjunctionFor: 'per',
Expand Down
1 change: 1 addition & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ const translations: TranslationDeepObject<typeof en> = {
na: '該当なし',
noResultsFound: '結果が見つかりません',
noResultsFoundMatching: (searchString: string) => `"${searchString}" に一致する結果は見つかりませんでした`,
suggestionsAvailableFor: (searchString: string) => (searchString ? `「${searchString}」の候補が利用可能です。` : '候補が利用可能です。'),
recentDestinations: '最近の宛先',
timePrefix: 'それは',
conjunctionFor: '〜用',
Expand Down
1 change: 1 addition & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ const translations: TranslationDeepObject<typeof en> = {
na: 'n.v.t.',
noResultsFound: 'Geen resultaten gevonden',
noResultsFoundMatching: (searchString: string) => `Geen resultaten gevonden voor "${searchString}"`,
suggestionsAvailableFor: (searchString: string) => (searchString ? `Suggesties beschikbaar voor "${searchString}".` : 'Suggesties beschikbaar.'),
recentDestinations: 'Recente bestemmingen',
timePrefix: 'Het is',
conjunctionFor: 'voor',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ const translations: TranslationDeepObject<typeof en> = {
na: 'ND dotyczy',
noResultsFound: 'Nie znaleziono wyników',
noResultsFoundMatching: (searchString: string) => `Nie znaleziono wyników pasujących do „${searchString}”`,
suggestionsAvailableFor: (searchString: string) => (searchString ? `Dostępne sugestie dla „${searchString}”.` : 'Dostępne sugestie.'),
recentDestinations: 'Ostatnie miejsca docelowe',
timePrefix: 'To jest',
conjunctionFor: 'dla',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ const translations: TranslationDeepObject<typeof en> = {
na: 'N/D',
noResultsFound: 'Nenhum resultado encontrado',
noResultsFoundMatching: (searchString: string) => `Nenhum resultado encontrado para "${searchString}"`,
suggestionsAvailableFor: (searchString: string) => (searchString ? `Sugestões disponíveis para "${searchString}".` : 'Sugestões disponíveis.'),
recentDestinations: 'Destinos recentes',
timePrefix: 'É',
conjunctionFor: 'para',
Expand Down
3 changes: 2 additions & 1 deletion src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ const translations: TranslationDeepObject<typeof en> = {
send: '发送',
na: '不适用',
noResultsFound: '未找到结果',
noResultsFoundMatching: (searchString: string) => `未找到与“${searchString}”匹配的结果`,
noResultsFoundMatching: (searchString: string) => `未找到与”${searchString}”匹配的结果`,
suggestionsAvailableFor: (searchString: string) => (searchString ? `”${searchString}”的建议可用。` : '建议可用。'),
recentDestinations: '最近目的地',
timePrefix: '它是',
conjunctionFor: '用于',
Expand Down
Loading