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 1324919
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 156 deletions.
2 changes: 1 addition & 1 deletion itou/templates/layout/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<html lang="fr">
<head>
<meta charset="utf-8">
<title>
<title id="page-title">
{% block title %}- Les emplois de l'inclusion{% endblock %}
</title>
{% block meta_description %}
Expand Down
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>
33 changes: 33 additions & 0 deletions itou/templates/search/includes/siaes_search_results.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<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 id="page-title" hx-swap-oob="true">
{# Cannot use block in includes #}
{# Keep in sync with the page 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 %}
- 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>
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>
84 changes: 18 additions & 66 deletions itou/templates/search/siaes_search_results.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{% extends "layout/base.html" %}
{% load str_filters %}
{% load matomo %}
{% load static %}

{% block title %}
{# Keep in sync with title out-of-band swap from itou/templates/search/includes/siaes_search_results.html #}
{% if form.is_valid %}
Emplois inclusifs à {{ distance }} km du centre de {{ city }}
{% include "includes/pagination_for_title.html" with page=results_page only %}
Expand All @@ -19,68 +19,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 +45,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 1324919

Please sign in to comment.