Skip to content

Commit

Permalink
factor autocomplete
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastienReuiller committed Feb 9, 2024
1 parent f2af8eb commit 51e23c6
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 137 deletions.
6 changes: 6 additions & 0 deletions lemarche/api/perimeters/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 5 additions & 3 deletions lemarche/api/perimeters/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
8 changes: 1 addition & 7 deletions lemarche/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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")
Expand Down
115 changes: 0 additions & 115 deletions lemarche/static/js/city_autocomplete_field.js

This file was deleted.

27 changes: 17 additions & 10 deletions lemarche/static/js/perimeter_autocomplete_field.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -220,7 +227,7 @@ class PerimetersMultiAutocomplete {
inputValue(result) {
return "";
}

inputValueHiddenField(result) {
// we want to avoid clicks outside that return 'undefined'
if (result) {
Expand All @@ -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 = '<strong>' + resultName + '</strong>';
if (resultKind) {
nameWithKind += ' <small>(' + resultKind + ')</small>';
Expand All @@ -266,7 +273,7 @@ class PerimetersMultiAutocomplete {
$(`#${idRefInput}`).remove();
$(this).remove();
}

createHiddenInputPerimeter(resultId, resultName) {
let removeIcon = $('<i>', { class: "ri-close-line font-weight-bold mr-0", "aria-hidden": true });
let resultIdString = `${this.perimeter_hidden_input_selector_prefix}-${resultId}`;
Expand Down
3 changes: 1 addition & 2 deletions lemarche/templates/siaes/search_results.html
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,6 @@ <h1 class="h4 mb-0">
{% block extra_js %}
<script type="text/javascript" src="{% static 'vendor/[email protected]'%}" defer></script>
<script type="text/javascript" src="{% static 'js/perimeter_autocomplete_field.js' %}"></script>
<script type="text/javascript" src="{% static 'js/city_autocomplete_field.js' %}"></script>
<script type="text/javascript" src="{% static 'js/search_form.js' %}"></script>
<script type="text/javascript">

Expand Down Expand Up @@ -368,7 +367,7 @@ <h1 class="h4 mb-0">
{% endif %}

// init city form fields
const cityAutoComplete = new CityAutocomplete("dir_form_city", "id_city");
const cityAutoComplete = new PerimeterAutocomplete("dir_form_city", "id_city", "Ville", "CITY");
cityAutoComplete.init();
});
</script>
Expand Down

0 comments on commit 51e23c6

Please sign in to comment.