Implement ComboAdresseSearch

This commit is contained in:
Paul Chavard 2020-10-07 17:44:04 +02:00
parent b6c94a3758
commit 8a2f079acb
6 changed files with 60 additions and 96 deletions

View file

@ -11,3 +11,7 @@
margin-top: 5px;
}
}
.form [data-react-class='MapEditor'] [data-reach-combobox-input] {
margin-bottom: 0;
}

View file

@ -0,0 +1,44 @@
import React, { useCallback } from 'react';
import { ReactQueryCacheProvider } from 'react-query';
import PropTypes from 'prop-types';
import ComboSearch from './ComboSearch';
import { queryCache } from './shared/queryCache';
function ComboAdresseSearch({
mandatory,
placeholder,
hiddenFieldId,
onChange,
transformResult = ({ properties: { label } }) => [label, label],
allowInputValues = true
}) {
const transformResults = useCallback((_, { features }) => features);
return (
<ReactQueryCacheProvider queryCache={queryCache}>
<ComboSearch
placeholder={placeholder}
required={mandatory}
hiddenFieldId={hiddenFieldId}
onChange={onChange}
allowInputValues={allowInputValues}
scope="adresse"
minimumInputLength={2}
transformResult={transformResult}
transformResults={transformResults}
/>
</ReactQueryCacheProvider>
);
}
ComboAdresseSearch.propTypes = {
placeholder: PropTypes.string,
mandatory: PropTypes.bool,
hiddenFieldId: PropTypes.string,
transformResult: PropTypes.func,
allowInputValues: PropTypes.bool,
onChange: PropTypes.func
};
export default ComboAdresseSearch;

View file

@ -1,88 +0,0 @@
import React, { useState, useEffect } from 'react';
import { getJSON } from '@utils';
import {
Combobox,
ComboboxInput,
ComboboxPopover,
ComboboxList,
ComboboxOption
} from '@reach/combobox';
import '@reach/combobox/styles.css';
import PropTypes from 'prop-types';
let cache = {};
const useAddressSearch = (searchTerm) => {
const [addresses, setAddresses] = useState([]);
useEffect(() => {
if (searchTerm.trim() !== '') {
let isFresh = true;
fetchAddresses(searchTerm).then((addresses) => {
if (isFresh) setAddresses(addresses);
});
return () => (isFresh = false);
}
}, [searchTerm]);
return addresses;
};
const fetchAddresses = (value) => {
if (cache[value]) {
return Promise.resolve(cache[value]);
}
const url = `https://api-adresse.data.gouv.fr/search/`;
return getJSON(url, { q: value, limit: 5 }, 'get').then((result) => {
if (result) {
cache[value] = result;
}
return result;
});
};
const SearchInput = ({ getCoords }) => {
const [searchTerm, setSearchTerm] = useState('');
const addresses = useAddressSearch(searchTerm);
const handleSearchTermChange = (event) => {
setSearchTerm(event.target.value);
};
return (
<Combobox aria-label="addresses">
<ComboboxInput
placeholder="Rechercher une adresse : saisissez au moins 2 caractères"
className="address-search-input"
style={{
font: 'inherit',
padding: '.25rem .5rem',
width: '100%',
minHeight: '62px'
}}
onChange={handleSearchTermChange}
/>
{addresses.features && (
<ComboboxPopover className="shadow-popup">
{addresses.features.length > 0 ? (
<ComboboxList>
{addresses.features.map((feature) => {
const str = `${feature.properties.name}, ${feature.properties.city}`;
return (
<ComboboxOption
onClick={() => getCoords(feature.geometry.coordinates)}
key={str}
value={str}
/>
);
})}
</ComboboxList>
) : (
<span style={{ display: 'block', margin: 8 }}>Aucun résultat</span>
)}
</ComboboxPopover>
)}
</Combobox>
);
};
SearchInput.propTypes = {
getCoords: PropTypes.func
};
export default SearchInput;

View file

@ -9,7 +9,7 @@ import { getJSON, ajax, fire } from '@utils';
import { getMapStyle, SwitchMapStyle } from '../MapStyles';
import SearchInput from './SearchInput';
import ComboAdresseSearch from '../ComboAdresseSearch';
import {
polygonCadastresFill,
polygonCadastresLine,
@ -279,9 +279,11 @@ function MapEditor({ featureCollection, url, preview, options }) {
marginBottom: '50px'
}}
>
<SearchInput
getCoords={(searchTerm) => {
setCoords(searchTerm);
<ComboAdresseSearch
placeholder="Rechercher une adresse : saisissez au moins 2 caractères"
allowInputValues={false}
onChange={(_, { geometry: { coordinates } }) => {
setCoords(coordinates);
setZoom([17]);
}}
/>

View file

@ -0,0 +1,3 @@
import Loadable from '../components/Loadable';
export default Loadable(() => import('../components/ComboAdresseSearch'));

View file

@ -1,4 +1,3 @@
= form.select :value, [champ.value].compact,
{ include_blank: true },
required: champ.mandatory?,
class: 'select2 adresse'
- hidden_field_id = SecureRandom.uuid
= form.hidden_field :value, { data: { uuid: hidden_field_id } }
= react_component("ComboAdresseSearch", mandatory: champ.mandatory?, hiddenFieldId: hidden_field_id)