Skip to content

Commit 79b556b

Browse files
committed
Display “No match found” error message when user input has no autocomplete results; background color of grouped title Organizations & Addresses
1 parent 04c1164 commit 79b556b

1 file changed

Lines changed: 70 additions & 30 deletions

File tree

client/src/components/FoodSeeker/AddressDropDown.jsx

Lines changed: 70 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
InputAdornment,
55
MenuItem,
66
TextField,
7+
useTheme,
78
} from "@mui/material";
89
import { useMapboxGeocoder } from "hooks/useMapboxGeocoder";
910
import { useEffect, useState } from "react";
@@ -19,6 +20,7 @@ import {
1920
import { useMapbox } from "../../hooks/useMapbox";
2021

2122
export default function AddressDropDown({ autoFocus }) {
23+
const theme = useTheme();
2224
const searchCoordinates = useSearchCoordinates();
2325
const userCoordinates = useUserCoordinates();
2426
const isWidget = useWidget();
@@ -32,6 +34,39 @@ export default function AddressDropDown({ autoFocus }) {
3234
const { flyTo } = useMapbox();
3335
const [highlightedOption, setHighlightedOption] = useState(null);
3436
const stakeholders = useStakeholders();
37+
38+
const stakeholderOptions = stakeholders?.map((stakeholder) => ({
39+
type: "stakeholder",
40+
value: stakeholder,
41+
}));
42+
const mapboxOptions = mapboxResults.slice(0, 10).map((result) => ({
43+
type: "mapbox",
44+
value: result,
45+
}));
46+
47+
const filteredStakeholders = stakeholderOptions.filter((option) => {
48+
if (inputVal.trim().length === 0) return true;
49+
return inputVal
50+
.toLowerCase()
51+
.split(" ")
52+
.every((word) =>
53+
getNameAndAddress(option.value).toLowerCase().includes(word)
54+
);
55+
});
56+
57+
// Only show "no match" message if user has typed input, loading is done, no results found,
58+
// AND the input doesn't match the currently selected location (to avoid showing message after selection)
59+
const showNoMatch =
60+
!isLoading &&
61+
inputVal.trim().length > 0 &&
62+
mapboxOptions.length === 0 &&
63+
filteredStakeholders.length === 0 &&
64+
inputVal !== searchCoordinates?.locationName;
65+
66+
const combinedOptions = showNoMatch
67+
? [{ type: "no-match", value: null }]
68+
: [...mapboxOptions, ...filteredStakeholders];
69+
3570
useEffect(() => {
3671
if (userCoordinates) {
3772
setInputVal("");
@@ -144,6 +179,21 @@ export default function AddressDropDown({ autoFocus }) {
144179

145180
const renderOption = (props, option) => {
146181
const { id } = props;
182+
183+
if (option.type === "no-match") {
184+
return (
185+
<MenuItem
186+
{...props}
187+
key="no-match"
188+
component="div"
189+
disabled
190+
sx={{ fontStyle: "italic", color: "text.secondary" }}
191+
>
192+
No match found
193+
</MenuItem>
194+
);
195+
}
196+
147197
return (
148198
<MenuItem
149199
{...props}
@@ -156,25 +206,16 @@ export default function AddressDropDown({ autoFocus }) {
156206
);
157207
};
158208

159-
const stakeholderOptions = stakeholders?.map((stakeholder) => ({
160-
type: "stakeholder",
161-
value: stakeholder,
162-
}));
163-
const mapboxOptions = mapboxResults.slice(0, 10).map((result) => ({
164-
type: "mapbox",
165-
value: result,
166-
}));
167-
168209
const handleKeyDown = (event) => {
169-
if (event.key === "Enter" && mapboxOptions.length > 0 && !isLoading) {
210+
if (event.key === "Enter" && !isLoading) {
170211
event.preventDefault();
171-
const selected = highlightedOption ?? mapboxOptions[0];
172-
handleAutocompleteOnChange(selected);
212+
if (mapboxOptions.length > 0) {
213+
const selected = highlightedOption ?? mapboxOptions[0];
214+
handleAutocompleteOnChange(selected);
215+
}
173216
}
174217
};
175218

176-
const combinedOptions = [...mapboxOptions, ...stakeholderOptions];
177-
178219
return (
179220
<>
180221
<Autocomplete
@@ -194,22 +235,13 @@ export default function AddressDropDown({ autoFocus }) {
194235
setInputVal(newValue ? getOptionLabel(newValue) : "");
195236
}}
196237
options={combinedOptions}
197-
groupBy={(option) =>
198-
option.type === "stakeholder" ? "Organizations" : "Addresses"
199-
}
238+
groupBy={(option) => {
239+
if (option.type === "no-match") return "";
240+
return option.type === "stakeholder" ? "Organizations" : "Addresses";
241+
}}
200242
getOptionLabel={getOptionLabel}
201-
filterOptions={(options, { inputValue }) => {
202-
return options.filter((option) => {
203-
if (option.type === "stakeholder") {
204-
return inputValue
205-
.toLowerCase()
206-
.split(" ")
207-
.every((word) =>
208-
getNameAndAddress(option.value).toLowerCase().includes(word)
209-
);
210-
}
211-
return true; // For mapbox results, we don't filter by inputValue
212-
});
243+
filterOptions={(options) => {
244+
return options;
213245
}}
214246
sx={{
215247
width: 600,
@@ -234,8 +266,13 @@ export default function AddressDropDown({ autoFocus }) {
234266
},
235267
}}
236268
ListboxProps={{
237-
style: {
269+
sx: {
238270
maxHeight: "160px",
271+
"& .MuiAutocomplete-groupLabel": {
272+
backgroundColor: theme.palette.filterButtons.backgroundColor,
273+
color: theme.palette.headingText.main,
274+
fontWeight: 600,
275+
},
239276
},
240277
}}
241278
renderInput={(params) => renderInput(params)}
@@ -255,6 +292,9 @@ function getNameAndAddress(stakeholder) {
255292
}
256293

257294
export function getOptionLabel(option) {
295+
if (option.type === "no-match") {
296+
return "No match found";
297+
}
258298
if (option.type === "stakeholder") {
259299
return getNameAndAddress(option.value);
260300
}

0 commit comments

Comments
 (0)