diff --git a/src/components/pages/ProvidersStep/ProvidersStep.tsx b/src/components/pages/ProvidersStep/ProvidersStep.tsx index 7c15d1f..a9f9992 100644 --- a/src/components/pages/ProvidersStep/ProvidersStep.tsx +++ b/src/components/pages/ProvidersStep/ProvidersStep.tsx @@ -10,6 +10,7 @@ import Menu from '@mui/material/Menu'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; import ToggleButton from '@mui/material/ToggleButton'; import SwapVertIcon from '@mui/icons-material/SwapVert'; +import SearchIcon from '@mui/icons-material/Search'; import ViewListOutlinedIcon from '@mui/icons-material/ViewListOutlined'; import MapOutlinedIcon from '@mui/icons-material/MapOutlined'; import LocationOnOutlinedIcon from '@mui/icons-material/LocationOnOutlined'; @@ -19,6 +20,7 @@ import { ProviderCard } from '../../molecules/ProviderCard'; import { FilterPanel } from '../../molecules/FilterPanel'; import { Button } from '../../atoms/Button'; import { Chip } from '../../atoms/Chip'; +import { IconButton } from '../../atoms/IconButton'; import { Switch } from '../../atoms/Switch'; import { Typography } from '../../atoms/Typography'; import { Divider } from '../../atoms/Divider'; @@ -246,6 +248,18 @@ export const ProvidersStep: React.FC = ({ // ─── Local state ─── const [sortAnchor, setSortAnchor] = React.useState(null); + // Draft value for the sticky search input — only committed (promoted to a + // chip) on Enter or when the search button is clicked. searchQuery is the + // committed filter value; the draft lives here until the user confirms. + const [searchDraft, setSearchDraft] = React.useState(''); + + const commitSearch = (next: string) => { + const trimmed = next.trim(); + if (!trimmed) return; + onSearchChange(trimmed); + onSearch?.(trimmed); + setSearchDraft(''); + }; // ─── Price input local state (commits on blur / Enter) ─── const [priceMinInput, setPriceMinInput] = React.useState(String(filterValues.priceRange[0])); @@ -395,27 +409,82 @@ export const ProvidersStep: React.FC = ({ borderColor: 'divider', }} > - {/* Location search */} - onSearchChange(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Enter' && onSearch) { - e.preventDefault(); - onSearch(searchQuery); + {/* Location search — committed location renders as a chip inside the + input. Typing produces a draft; Enter or the search button commit + it. Deleting the chip clears the committed filter. */} + { + // Ignore the 'reset' input-change Autocomplete fires after a value + // commit (it echoes the committed value back into the input and + // would otherwise re-populate the draft we just cleared). + if (reason === 'reset') return; + setSearchDraft(newDraft); + }} + onChange={(_, newValue) => { + if (newValue.length === 0) { + // Chip removed — clear the committed filter + onSearchChange(''); + return; } + // Commit the most-recent entry (cap at 1 location) + const last = newValue[newValue.length - 1]; + if (typeof last === 'string') commitSearch(last); }} - fullWidth - size="small" - InputProps={{ - startAdornment: ( - - - - ), - }} + renderTags={(value, getTagProps) => + value.map((option, index) => { + const { key, ...chipProps } = getTagProps({ index }); + return ( + + ); + }) + } + renderInput={(params) => ( + + + + + {params.InputProps.startAdornment} + + ), + endAdornment: ( + + commitSearch(searchDraft)} + disabled={!searchDraft.trim()} + > + + + + ), + }} + /> + )} sx={{ mb: 1.5 }} />