Skip to content

Commit

Permalink
Use HTMX for employers/job search
Browse files Browse the repository at this point in the history
Avoid reloading the entire page (and scrolling up) when a single filter
changes.

The goal is for the filter form not to be reloaded, to keep the current
scroll position on the page and collapse state. This necessitated
reorganizing the page so that the tabs, heading section and certain form
fields can be reloaded independently with out-of-brand swaps.

Purposely don’t move back to the top of the results. With the redesign
in progress, the filters will move to the top of the page, removing the
need to scroll. Also, as the filter list can be quite tall, users
picking filters from the bottom of the page would be quite annoyed when
the scroll position changes after they picked an element.
  • Loading branch information
francoisfreitag committed Apr 18, 2024
1 parent cec17df commit 233696b
Show file tree
Hide file tree
Showing 13 changed files with 277 additions and 166 deletions.
85 changes: 2 additions & 83 deletions itou/templates/search/includes/siaes_search_filters.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,89 +11,8 @@
{% bootstrap_field form.distance wrapper_class="form-group mb-0" label_class="d-block font-weight-bold mb-3" %}
</fieldset>

{% if form.departments %}
<hr>
<fieldset>
<div class="form-group mb-0">
<legend class="has-collapse-caret mb-0"
data-bs-toggle="collapse"
href="#collapse_{{ form.departments.name }}"
role="button"
aria-expanded="{% if form.departments.value %}true{% else %}false{% endif %}"
aria-controls="collapse_{{ form.departments.name }}">
{{ form.departments.label | capfirst }}
</legend>
<div class="collapse mt-3{% if form.departments.value %} show{% endif %}" id="collapse_{{ form.departments.name }}">
{{ form.departments }}
</div>
</div>
</fieldset>
{% endif %}

{# getattr and list still painful in Django template #}
{% if form.districts_13 %}
<hr>
<fieldset>
<div class="form-group mb-0">
<legend class="has-collapse-caret mb-0"
data-bs-toggle="collapse"
href="#collapse_{{ form.districts_13.name }}"
role="button"
aria-expanded="{% if form.districts_13.value %}true{% else %}false{% endif %}"
aria-controls="collapse_{{ form.districts_13.name }}">
{{ form.districts_13.label | capfirst }}
</legend>
<div class="collapse mt-3{% if form.districts_13.value %} show{% endif %}" id="collapse_{{ form.districts_13.name }}">
{{ form.districts_13 }}
</div>
</div>
</fieldset>
{% endif %}

{% if form.districts_69 %}
<hr>
<fieldset>
<div class="form-group mb-0">
<legend class="has-collapse-caret mb-0"
data-bs-toggle="collapse"
href="#collapse_{{ form.districts_69.name }}"
role="button"
aria-expanded="{% if form.districts_69.value %}true{% else %}false{% endif %}"
aria-controls="collapse_{{ form.districts_69.name }}">
{{ form.districts_69.label | capfirst }}
</legend>
<div class="collapse mt-3{% if form.districts_69.value %} show{% endif %}" id="collapse_{{ form.districts_69.name }}">
{{ form.districts_69 }}
</div>
</div>
</fieldset>
{% endif %}

{% if form.districts_75 %}
<hr>
<fieldset>
<div class="form-group mb-0">
<legend class="has-collapse-caret mb-0"
data-bs-toggle="collapse"
href="#collapse_{{ form.districts_75.name }}"
role="button"
aria-expanded="{% if form.districts_75.value %}true{% else %}false{% endif %}"
aria-controls="collapse_{{ form.districts_75.name }}">
{{ form.districts_75.label | capfirst }}
</legend>
<div class="collapse mt-3{% if form.districts_75.value %} show{% endif %}" id="collapse_{{ form.districts_75.name }}">
{{ form.districts_75 }}
</div>
</div>
</fieldset>
{% endif %}

{% if form.company %}
<hr>
<fieldset>
{% bootstrap_field form.company wrapper_class="form-group mb-0" label_class="d-block font-weight-bold mb-3" %}
</fieldset>
{% endif %}
{% include "search/includes/siaes_search_filters_departments.html" %}
{% include "search/includes/siaes_search_filters_company.html" %}

<hr>
<fieldset>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% load django_bootstrap5 %}
<div id="company-field"{% if request.htmx %} hx-swap-oob="true"{% endif %}>
{% if form.company %}
<hr>
<fieldset>
{% bootstrap_field form.company wrapper_class="form-group mb-0" label_class="d-block font-weight-bold mb-3" %}
</fieldset>
{% endif %}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
{% load django_bootstrap5 %}
<div id="department-fields"{% if request.htmx %} hx-swap-oob="true"{% endif %}>
{% if form.departments %}
<hr>
<fieldset>
<div class="form-group mb-0">
<legend class="has-collapse-caret mb-0"
data-bs-toggle="collapse"
href="#collapse_{{ form.departments.name }}"
role="button"
aria-expanded="{% if form.departments.value %}true{% else %}false{% endif %}"
aria-controls="collapse_{{ form.departments.name }}">
{{ form.departments.label | capfirst }}
</legend>
<div class="collapse mt-3{% if form.departments.value %} show{% endif %}" id="collapse_{{ form.departments.name }}">
{{ form.departments }}
</div>
</div>
</fieldset>
{% endif %}

{# getattr and list still painful in Django template #}
{% if form.districts_13 %}
<hr>
<fieldset>
<div class="form-group mb-0">
<legend class="has-collapse-caret mb-0"
data-bs-toggle="collapse"
href="#collapse_{{ form.districts_13.name }}"
role="button"
aria-expanded="{% if form.districts_13.value %}true{% else %}false{% endif %}"
aria-controls="collapse_{{ form.districts_13.name }}">
{{ form.districts_13.label | capfirst }}
</legend>
<div class="collapse mt-3{% if form.districts_13.value %} show{% endif %}" id="collapse_{{ form.districts_13.name }}">
{{ form.districts_13 }}
</div>
</div>
</fieldset>
{% endif %}

{% if form.districts_69 %}
<hr>
<fieldset>
<div class="form-group mb-0">
<legend class="has-collapse-caret mb-0"
data-bs-toggle="collapse"
href="#collapse_{{ form.districts_69.name }}"
role="button"
aria-expanded="{% if form.districts_69.value %}true{% else %}false{% endif %}"
aria-controls="collapse_{{ form.districts_69.name }}">
{{ form.districts_69.label | capfirst }}
</legend>
<div class="collapse mt-3{% if form.districts_69.value %} show{% endif %}" id="collapse_{{ form.districts_69.name }}">
{{ form.districts_69 }}
</div>
</div>
</fieldset>
{% endif %}

{% if form.districts_75 %}
<hr>
<fieldset>
<div class="form-group mb-0">
<legend class="has-collapse-caret mb-0"
data-bs-toggle="collapse"
href="#collapse_{{ form.districts_75.name }}"
role="button"
aria-expanded="{% if form.districts_75.value %}true{% else %}false{% endif %}"
aria-controls="collapse_{{ form.districts_75.name }}">
{{ form.districts_75.label | capfirst }}
</legend>
<div class="collapse mt-3{% if form.districts_75.value %} show{% endif %}" id="collapse_{{ form.districts_75.name }}">
{{ form.districts_75 }}
</div>
</div>
</fieldset>
{% endif %}
</div>
27 changes: 27 additions & 0 deletions itou/templates/search/includes/siaes_search_results.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<div id="job-search-results" class="col-12 col-md-8">
{% for item in results_page %}
{% if request.resolver_match.view_name == "search:employers_results" %}
{% include "companies/includes/_card_siae.html" with siae=item %}
{% else %}
{% include "companies/includes/_card_jobdescription.html" with job_description=item %}
{% endif %}
{% empty %}
<div class="c-box c-box--results mb-3 mb-md-4">
<div class="c-box--results__body">
<p class="mb-0">Aucun résultat avec les filtres actuels.</p>
</div>
</div>
{% endfor %}
{% include "includes/pagination.html" with page=results_page boost=True boost_target="#job-search-results" boost_indicator="#job-search-results" %}
</div>
{% if request.htmx %}
<title hx-swap-oob="outerHTML,title">
{% include "search/includes/siaes_search_title.html" %}
{# Cannot use block in includes #}
- Les emplois de l'inclusion
</title>
{% include "search/includes/siaes_search_filters_company.html" %}
{% include "search/includes/siaes_search_filters_departments.html" %}
{% include "search/includes/siaes_search_top.html" %}
{% include "search/includes/siaes_search_tabs.html" %}
{% endif %}
22 changes: 22 additions & 0 deletions itou/templates/search/includes/siaes_search_tabs.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{% load matomo %}
{% load str_filters %}
<ul id="job-search-tabs" class="s-tabs-01__nav nav nav-tabs mt-3"{% if request.htmx %} hx-swap-oob="true"{% endif %}>
<li class="nav-item">
<a class="nav-link{% if request.resolver_match.view_name == "search:employers_results" %} active{% endif %}"
{% matomo_event "candidature" "clic" "clic-onglet-employeur" %}
href="{% url "search:employers_results" %}?{{ filters_query_string }}">
<i class="ri-hotel-line font-weight-normal me-1" aria-hidden="true"></i>
<span>Employeur{{ siaes_count|pluralizefr }}</span>
<span class="badge badge-sm rounded-pill ms-2">{{ siaes_count }}</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.resolver_match.view_name == "search:job_descriptions_results" %} active{% endif %}"
{% matomo_event "candidature" "clic" "clic-onglet-fichesdeposte" %}
href="{% url "search:job_descriptions_results" %}?{{ filters_query_string }}">
<i class="ri-briefcase-4-line font-weight-normal me-1" aria-hidden="true"></i>
<span>Poste{{ job_descriptions_count|pluralizefr }} <span class="d-none d-md-inline">ouvert{{ job_descriptions_count|pluralizefr }} au recrutement</span></span>
<span class="badge badge-sm rounded-pill ms-2">{{ job_descriptions_count }}</span>
</a>
</li>
</ul>
6 changes: 6 additions & 0 deletions itou/templates/search/includes/siaes_search_title.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% if form.is_valid %}
Emplois inclusifs à {{ distance }} km du centre de {{ city }}
{% include "includes/pagination_for_title.html" with page=results_page only %}
{% else %}
Rechercher un emploi inclusif
{% endif %}
20 changes: 20 additions & 0 deletions itou/templates/search/includes/siaes_search_top.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% load str_filters %}
<div id="job-search-top"{% if request.htmx %} hx-swap-oob="true"{% endif %}>
{% if request.resolver_match.view_name == "search:employers_results" %}
<h2>Employeur{{ siaes_count|pluralizefr }}</h2>
<p>
{{ siaes_count }} résultat{{ siaes_count|pluralizefr }}
{% if form.is_valid %}
- Emplois inclusifs à <strong>{{ distance }} km</strong> du centre de <strong>{{ city }}</strong>
{% endif %}
</p>
{% else %}
<h2>Poste{{ job_descriptions_count|pluralizefr }} ouvert{{ job_descriptions_count|pluralizefr }} au recrutement</h2>
<p>
{{ job_descriptions_count }} résultat{{ job_descriptions_count|pluralizefr }}
{% if form.is_valid %}
- Emplois inclusifs à <strong>{{ distance }} km</strong> du centre de <strong>{{ city }}</strong>
{% endif %}
</p>
{% endif %}
</div>
90 changes: 18 additions & 72 deletions itou/templates/search/siaes_search_results.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
{% extends "layout/base.html" %}
{% load str_filters %}
{% load matomo %}
{% load static %}

{% block title %}
{% if form.is_valid %}
Emplois inclusifs à {{ distance }} km du centre de {{ city }}
{% include "includes/pagination_for_title.html" with page=results_page only %}
{% else %}
Rechercher un emploi inclusif
{% endif %}
{% include "search/includes/siaes_search_title.html" %}
{{ block.super }}
{% endblock %}

Expand All @@ -19,68 +13,24 @@
<div class="s-tabs-01__container container">
<div class="s-tabs-01__row row">
<div class="s-tabs-01__col col-12">
<form id="search-form" method="get" class="d-block w-100">
{% include "search/includes/siaes_search_form.html" with form=form %}
<ul class="s-tabs-01__nav nav nav-tabs mt-3">
<li class="nav-item">
<a class="nav-link{% if request.resolver_match.view_name == "search:employers_results" %} active{% endif %}"
{% matomo_event "candidature" "clic" "clic-onglet-employeur" %}
href="{% url "search:employers_results" %}?{{ filters_query_string }}">
<i class="ri-hotel-line font-weight-normal me-1" aria-hidden="true"></i>
<span>Employeur{{ siaes_count|pluralizefr }}</span>
<span class="badge badge-sm rounded-pill ms-2">{{ siaes_count }}</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.resolver_match.view_name == "search:job_descriptions_results" %} active{% endif %}"
{% matomo_event "candidature" "clic" "clic-onglet-fichesdeposte" %}
href="{% url "search:job_descriptions_results" %}?{{ filters_query_string }}">
<i class="ri-briefcase-4-line font-weight-normal me-1" aria-hidden="true"></i>
<span>Poste{{ job_descriptions_count|pluralizefr }} <span class="d-none d-md-inline">ouvert{{ job_descriptions_count|pluralizefr }} au recrutement</span></span>
<span class="badge badge-sm rounded-pill ms-2">{{ job_descriptions_count }}</span>
</a>
</li>
</ul>
<div class="tab-content">
{% if request.resolver_match.view_name == "search:employers_results" %}
<h2>Employeur{{ siaes_count|pluralizefr }}</h2>
<p>
{{ siaes_count }} résultat{{ siaes_count|pluralizefr }}
{% if form.is_valid %}
- Emplois inclusifs à <strong>{{ distance }} km</strong> du centre de <strong>{{ city }}</strong>
{% endif %}
</p>
{% else %}
<h2>Poste{{ job_descriptions_count|pluralizefr }} ouvert{{ job_descriptions_count|pluralizefr }} au recrutement</h2>
<p>
{{ job_descriptions_count }} résultat{{ job_descriptions_count|pluralizefr }}
{% if form.is_valid %}
- Emplois inclusifs à <strong>{{ distance }} km</strong> du centre de <strong>{{ city }}</strong>
{% endif %}
</p>
{% endif %}
{% include "search/includes/siaes_search_form.html" with form=form %}
{% include "search/includes/siaes_search_tabs.html" %}
<div class="tab-content">
{% include "search/includes/siaes_search_top.html" %}
<form class="d-block w-100"
hx-get="{% url request.resolver_match.view_name %}"
hx-trigger="change delay:.5s, change from:#id_city"
hx-indicator="#job-search-results"
hx-target="#job-search-results"
hx-swap="outerHTML"
hx-include="#id_city"
hx-push-url="true">
<div class="row">
<div class="col-12 col-md-4">{% include "search/includes/siaes_search_filters.html" with form=form %}</div>
<div class="col-12 col-md-8">
{% for item in results_page %}
{% if request.resolver_match.view_name == "search:employers_results" %}
{% include "companies/includes/_card_siae.html" with siae=item %}
{% else %}
{% include "companies/includes/_card_jobdescription.html" with job_description=item %}
{% endif %}
{% empty %}
<div class="c-box c-box--results mb-3 mb-md-4">
<div class="c-box--results__body">
<p class="mb-0">Aucun résultat avec les filtres actuels.</p>
</div>
</div>
{% endfor %}

{% include "includes/pagination.html" with page=results_page %}
</div>
{% include "search/includes/siaes_search_results.html" %}
</div>
</div>
</form>
</form>
</div>
</div>
</div>
</div>
Expand All @@ -89,11 +39,7 @@ <h2>Poste{{ job_descriptions_count|pluralizefr }} ouvert{{ job_descriptions_coun

{% block script %}
{{ block.super }}
<script nonce="{{ CSP_NONCE }}">
$("#asideFiltersCollapse :input").change(function() {
$("#search-form").submit();
});
</script>
<script src='{% static "js/htmx_compat.js" %}'></script>
{# A / B testing: apply to company with job descriptions #}
<script nonce="{{ CSP_NONCE }}">
var _paq = _paq || [];
Expand Down
Loading

0 comments on commit 233696b

Please sign in to comment.