diff --git a/lemarche/api/perimeters/tests.py b/lemarche/api/perimeters/tests.py
index dccf76c25..13c8ec9f6 100644
--- a/lemarche/api/perimeters/tests.py
+++ b/lemarche/api/perimeters/tests.py
@@ -93,6 +93,12 @@ def test_should_filter_perimeters_autocomplete_by_q_code(self):
self.assertEqual(len(response.data), 1 + 1)
self.assertEqual(response.data[0]["name"], "Isère")
+ def test_should_filter_perimeters_autocomplete_by_q_code_only_cities(self):
+ url = reverse("api:perimeters-autocomplete-list") + "?q=38&kind=CITY" # anonymous user
+ response = self.client.get(url)
+ self.assertEqual(len(response.data), 1)
+ self.assertEqual(response.data[0]["name"], "Grenoble")
+
def test_should_filter_perimeters_autocomplete_by_q_post_code(self):
url = reverse("api:perimeters-autocomplete-list") + "?q=38100" # anonymous user
response = self.client.get(url)
diff --git a/lemarche/api/perimeters/views.py b/lemarche/api/perimeters/views.py
index 7ea491c97..18a4b4b9b 100644
--- a/lemarche/api/perimeters/views.py
+++ b/lemarche/api/perimeters/views.py
@@ -41,9 +41,11 @@ def list(self, request, *args, **kwargs):
"""
return super().list(request, args, kwargs)
-
-class CityAutocompleteViewSet(PerimeterAutocompleteViewSet):
- queryset = Perimeter.objects.cities()
+ def get_queryset(self):
+ kind = self.request.query_params.get("kind", None)
+ if kind and kind in [id for (id, name) in Perimeter.KIND_CHOICES]:
+ return Perimeter.objects.filter(kind=kind)
+ return self.queryset
class PerimeterKindViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
diff --git a/lemarche/api/urls.py b/lemarche/api/urls.py
index 09a470253..0ab50ecfc 100644
--- a/lemarche/api/urls.py
+++ b/lemarche/api/urls.py
@@ -5,12 +5,7 @@
from lemarche.api.emails.views import InboundParsingEmailView
from lemarche.api.networks.views import NetworkViewSet
-from lemarche.api.perimeters.views import (
- CityAutocompleteViewSet,
- PerimeterAutocompleteViewSet,
- PerimeterKindViewSet,
- PerimeterViewSet,
-)
+from lemarche.api.perimeters.views import PerimeterAutocompleteViewSet, PerimeterKindViewSet, PerimeterViewSet
from lemarche.api.sectors.views import SectorViewSet
from lemarche.api.siaes.views import SiaeKindViewSet, SiaePrestaTypeViewSet, SiaeViewSet
from lemarche.api.tenders.views import TenderAmountViewSet, TenderKindViewSet, TenderViewSet
@@ -27,7 +22,6 @@
router.register(r"networks", NetworkViewSet, basename="networks")
router.register(r"perimeters/kinds", PerimeterKindViewSet, basename="perimeter-kinds")
router.register(r"perimeters/autocomplete", PerimeterAutocompleteViewSet, basename="perimeters-autocomplete")
-router.register(r"cities/autocomplete", CityAutocompleteViewSet, basename="cities-autocomplete")
router.register(r"perimeters", PerimeterViewSet, basename="perimeters")
router.register(r"tenders/kinds", TenderKindViewSet, basename="tender-kinds")
router.register(r"tenders/amounts", TenderAmountViewSet, basename="tender-amounts")
diff --git a/lemarche/static/js/city_autocomplete_field.js b/lemarche/static/js/city_autocomplete_field.js
deleted file mode 100644
index 462316ca0..000000000
--- a/lemarche/static/js/city_autocomplete_field.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
- * Accessible autocomplete for the city search form field
- * https://alphagov.github.io/accessible-autocomplete/examples/
- *
- * CityAutocomplete:
- * - single city
- */
-var API_ENDPOINT = '/api/cities/autocomplete/';
-
-async function fetchSource(query) {
- const res = await fetch(`${API_ENDPOINT}?q=${query}&results=10`);
- const data = await res.json();
- return data; // data.results
-}
-
-class CityAutocomplete {
- constructor(city_container_name, city_input_id) {
- this.city_container_name= city_container_name;
- this.city_input_id= city_input_id;
- this.city_name_input_id= `${this.city_input_id}_name`;
- this.cityAutocompleteContainer = document.getElementById(city_container_name);
- this.cityInput = document.getElementById(city_input_id); // hidden
- this.initial_value_name = this.cityAutocompleteContainer.dataset.inputValue;
- this.isInit = false;
- }
-
- init() {
- if(!this.isInit) {
- this.isInit = true;
- accessibleAutocomplete({
- element: this.cityAutocompleteContainer,
- id: this.city_name_input_id,
- name: this.city_name_input_id, // url GET param name
- placeholder: 'Ville',
- minLength: 2,
- defaultValue: this.initial_value_name,
- source: this.getSource,
- displayMenu: 'overlay',
- templates: {
- inputValue: this.inputValue, // returns the string value to be inserted into the input
- suggestion: this.inputValue, // used when rendering suggestions, and should return a string, which can contain HTML
- },
- autoselect: true,
- onConfirm: (confirmed) => {
- this.inputValueHiddenField(confirmed);
- },
- showNoOptionsFound: false,
- // Internationalization
- tNoResults: this.tNoResults,
- tStatusQueryTooShort: this.tStatusQueryTooShort,
- tStatusNoResults: this.tStatusNoResults,
- tStatusSelectedOption: this.tStatusSelectedOption,
- });
-
- // after creation of input autocomplete, we set the div as attribute
- this.cityInputName = document.getElementById(this.city_name_input_id);
- }
- }
-
- tNoResults = () => 'Aucun résultat'
- tStatusQueryTooShort = (minQueryLength) => `Tapez au moins ${minQueryLength} caractères pour avoir des résultats`
- tStatusNoResults = () => 'Aucun résultat pour cette recherche'
- tStatusSelectedOption = (selectedOption, length, index) => `${selectedOption} ${index + 1} de ${length} est sélectionnée`
-
- async getSource(query, populateResults) {
- const res = await fetchSource(query);
- populateResults(res);
- }
-
- inputValue(result) {
- // strip html from suggestion
- if(!result) {
- return result;
- }
- let resultName, resultKind = '';
-
- // build resultName & resultKind from the result object
- if (typeof result === 'object') {
- resultName = result.name;
- resultKind = result.department_code;
- }
-
- // Edge case: if there is an initial value
- // reconstruct resultName & resultKind from the result string
- if (typeof result === 'string') {
- resultName = result.substring(0, result.lastIndexOf(' '));
- resultKind = result.includes('(') ? result.substring(result.lastIndexOf(' ') + 2, result.length - 1) : '';
- }
-
- let nameWithKind = '' + resultName + '';
- if (resultKind) {
- nameWithKind += ' (' + resultKind + ')';
- }
- return nameWithKind.replace(/(<([^>]+)>)/gi, '');
- }
-
- inputValueHiddenField(result) {
- // we want to avoid clicks outside that return 'undefined'
- if (result) {
- if (typeof result === 'object') {
- this.cityInput.value = result.slug;
- }
- }
- }
-
- resetInputValueHiddenField() {
- this.cityInput.value = '';
- }
-
- cleanCity() {
- this.cityInputName.value ='';
- this.cityInput.value ='';
- }
-
-}
diff --git a/lemarche/static/js/perimeter_autocomplete_field.js b/lemarche/static/js/perimeter_autocomplete_field.js
index ea7b634ea..54176ec56 100644
--- a/lemarche/static/js/perimeter_autocomplete_field.js
+++ b/lemarche/static/js/perimeter_autocomplete_field.js
@@ -29,16 +29,18 @@ const debounce = (callback, wait) => {
};
}
-async function fetchSource(query) {
- const res = await fetch(`${API_ENDPOINT}?q=${query}&results=10`);
+async function fetchSource(query, kind = undefined) {
+ const res = await fetch(`${API_ENDPOINT}?q=${query}&results=10${kind ? `&kind=${kind}` : ''}`);
const data = await res.json();
return data; // data.results
}
class PerimeterAutocomplete {
- constructor(perimeter_container_name, perimeter_input_id) {
+ constructor(perimeter_container_name, perimeter_input_id, perimeter_placeholder='Région, ville…', perimeter_kind = undefined) {
this.perimeter_container_name= perimeter_container_name;
this.perimeter_input_id= perimeter_input_id;
+ this.perimeter_kind= perimeter_kind;
+ this.perimeter_placeholder= perimeter_placeholder;
this.perimeter_name_input_id= `${this.perimeter_input_id}_name`;
this.perimeterAutocompleteContainer = document.getElementById(perimeter_container_name);
this.perimeterInput = document.getElementById(perimeter_input_id); // hidden
@@ -53,10 +55,10 @@ class PerimeterAutocomplete {
element: this.perimeterAutocompleteContainer,
id: this.perimeter_name_input_id,
name: this.perimeter_name_input_id, // url GET param name
- placeholder: 'Région, ville…', // 'Autour de (Arras, Bobigny, Strasbourg…)', 'Région, département, ville'
+ placeholder: this.perimeter_placeholder,
minLength: 2,
defaultValue: this.initial_value_name,
- source: this.getSource,
+ source: this.perimeter_kind === 'CITY' ? this.getSourceCity : this.getSource,
displayMenu: 'overlay',
templates: {
inputValue: this.inputValue, // returns the string value to be inserted into the input
@@ -89,6 +91,11 @@ class PerimeterAutocomplete {
populateResults(res);
}
+ async getSourceCity(query, populateResults) {
+ const res = await fetchSource(query, "CITY");
+ populateResults(res);
+ }
+
inputValue(result) {
// strip html from suggestion
if(!result) {
@@ -220,7 +227,7 @@ class PerimetersMultiAutocomplete {
inputValue(result) {
return "";
}
-
+
inputValueHiddenField(result) {
// we want to avoid clicks outside that return 'undefined'
if (result) {
@@ -239,20 +246,20 @@ class PerimetersMultiAutocomplete {
suggestion(result) {
// display suggestions as `name (kind)`
let resultName, resultKind = '';
-
+
// build resultName & resultKind from the result object
if (typeof result === 'object') {
resultName = result.name;
resultKind = (result.kind === 'CITY') ? result.department_code : KIND_MAPPING[result.kind];
}
-
+
// Edge case: if there is an initial value
// reconstruct resultName & resultKind from the result string
if (typeof result === 'string') {
resultName = result.substring(0, result.lastIndexOf(' '));
resultKind = result.includes('(') ? result.substring(result.lastIndexOf(' ') + 2, result.length - 1) : '';
}
-
+
let nameWithKind = '' + resultName + '';
if (resultKind) {
nameWithKind += ' (' + resultKind + ')';
@@ -266,7 +273,7 @@ class PerimetersMultiAutocomplete {
$(`#${idRefInput}`).remove();
$(this).remove();
}
-
+
createHiddenInputPerimeter(resultId, resultName) {
let removeIcon = $('', { class: "ri-close-line font-weight-bold mr-0", "aria-hidden": true });
let resultIdString = `${this.perimeter_hidden_input_selector_prefix}-${resultId}`;
diff --git a/lemarche/templates/siaes/search_results.html b/lemarche/templates/siaes/search_results.html
index 4fd1b35be..f6a0c7d3d 100644
--- a/lemarche/templates/siaes/search_results.html
+++ b/lemarche/templates/siaes/search_results.html
@@ -310,7 +310,6 @@
{% block extra_js %}
-