loko/streetup/assets/templates/assets/quick_inspection_map.html

266 lines
11 KiB
HTML

{% extends base_template|default:"base.html" %}
{% load i18n static %}
{% block title %}{% translate "Inspection Rapide Carte GPS" %}{% endblock %}
{% block extra_head %}
<link href="{% static 'common/maplibre-gl.css' %}" rel="stylesheet">
<style>
body {
padding-top: 54px !important;
padding-bottom: 0 !important;
}
main.container, main {
margin: 0 !important;
padding: 0 !important;
max-width: 100% !important;
width: 100% !important;
}
footer {
display: none !important;
}
#inspection-map-wrapper {
position: relative;
height: calc(100vh - 54px);
min-height: 500px;
width: 100%;
overflow: hidden;
}
#inspection-map {
min-height: 500px;
height: 100%;
width: 100%;
z-index: 1;
}
.map-controls-overlay {
position: absolute;
top: 6px;
left: 8px;
right: 8px;
z-index: 1000;
pointer-events: none;
}
.map-controls-overlay > * {
pointer-events: auto;
}
/* Transition fluide pour le repositionnement dynamique des contrôles MapLibre */
#inspection-map .maplibregl-ctrl-top-left,
#inspection-map .maplibregl-ctrl-top-right {
transition: margin-top 0.15s ease-out;
}
.map-floating-actions {
position: absolute;
bottom: 24px;
right: 16px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 8px;
}
.user-gps-dot {
width: 16px;
height: 16px;
background-color: #0d6efd;
border: 2px solid #ffffff;
border-radius: 50%;
box-shadow: 0 0 10px rgba(13, 110, 253, 0.8);
}
/* Bottom Sheet Modal Styling for Mobile */
.modal-bottom-sheet .modal-dialog {
margin: 0;
position: fixed;
bottom: 0;
left: 0;
right: 0;
max-width: 100%;
}
.modal-bottom-sheet .modal-content {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-top-left-radius: 1.25rem;
border-top-right-radius: 1.25rem;
border: none;
max-height: 85vh;
display: flex;
flex-direction: column;
}
.modal-bottom-sheet .modal-body {
max-height: 70vh;
overflow-y: auto;
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
}
.thematic-tile {
border: 2px solid #e9ecef;
border-radius: 0.85rem;
padding: 0.75rem 1rem;
transition: all 0.2s ease;
cursor: pointer;
background: #ffffff;
}
.thematic-tile.active {
border-color: #0d6efd;
background-color: rgba(13, 110, 253, 0.06);
}
.thematic-tile-icon {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
flex-shrink: 0;
}
.filter-btn-pill {
background-color: #ffffff;
border: 1px solid #dee2e6;
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
border-radius: 50rem;
padding: 0.4rem 0.85rem;
font-size: 0.85rem;
transition: all 0.15s ease;
}
.filter-btn-pill:active {
transform: scale(0.97);
}
</style>
{% endblock %}
{% block content %}
<div id="inspection-map-wrapper">
<!-- Overlay des filtres mémorisés (Boutons tactiles mobiles) -->
<div class="map-controls-overlay">
<div class="card shadow-sm border-0 bg-white opacity-95 rounded-4">
<div class="card-body p-2 d-flex align-items-center justify-content-between gap-2 flex-wrap">
<div class="d-flex align-items-center gap-1.5">
<i class="bi bi-geo-alt-fill text-primary fs-6"></i>
<span class="fw-bold small me-1">{% translate "Inspection Rapide" %}</span>
<span class="badge bg-light text-muted border small" id="gps-status-text">{% translate "GPS actif" %}</span>
</div>
<div class="d-flex align-items-center gap-2">
<!-- Bouton Déclencheur Thématique -->
<button id="btn-select-thematic" type="button" class="btn filter-btn-pill d-flex align-items-center gap-1.5" data-bs-toggle="modal" data-bs-target="#thematicChooserModal">
<i id="thematic-icon-display" class="bi bi-collection text-primary"></i>
<span id="thematic-name-display" class="fw-semibold">{% translate "Thématique" %}</span>
<i class="bi bi-chevron-down text-muted ms-1 small"></i>
</button>
<!-- Bouton Déclencheur Catégorie -->
<button id="btn-select-category" type="button" class="btn filter-btn-pill d-flex align-items-center gap-1.5" data-bs-toggle="modal" data-bs-target="#categoryChooserModal">
<i class="bi bi-tag-fill text-secondary"></i>
<span id="category-name-display" class="fw-semibold">{% translate "Catégorie" %}</span>
<i class="bi bi-chevron-down text-muted ms-1 small"></i>
</button>
</div>
</div>
</div>
<!-- Sélecteurs cachés synchronisés avec le JS d'inspection -->
<select id="filter-thematic" class="d-none">
<option value="">{% translate "-- Thématique --" %}</option>
{% for t in thematics %}
<option value="{{ t.code }}" data-icon="{{ t.icon|default:'bi-folder2' }}" data-name="{{ t.name }}" {% if t.code == 'parking' %}selected{% endif %}>{{ t.name }}</option>
{% endfor %}
</select>
<select id="filter-category" class="d-none">
<option value="">{% translate "-- Catégorie --" %}</option>
{% for c in categories %}
<option value="{{ c.id }}" data-thematic="{{ c.thematic.code }}" data-name="{{ c.get_name }}">{{ c.get_name }}</option>
{% endfor %}
</select>
<div id="map-warning-alert" class="alert alert-warning alert-dismissible fade show d-none shadow-sm py-2 px-3 mt-2 mb-0 small" role="alert">
<i class="bi bi-exclamation-triangle-fill me-1 text-warning"></i>
<span id="map-warning-text">{% translate "Veuillez zoomer sur la carte (zoom 16+) pour afficher les équipements." %}</span>
<button type="button" class="btn-close py-2" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</div>
<!-- Carte MapLibre -->
<div id="inspection-map"></div>
<!-- Actions Flottantes (Bouton GPS) -->
<div class="map-floating-actions">
<button id="btn-gps-locate" class="btn btn-white btn-lg shadow rounded-circle border" title="{% translate 'Ma position GPS' %}">
<i class="bi bi-crosshair text-primary fs-5"></i>
</button>
</div>
</div>
<!-- Modal Choix de Thématique (Style Mobile Bottom Sheet) -->
<div class="modal fade modal-bottom-sheet" id="thematicChooserModal" tabindex="-1" aria-labelledby="thematicChooserModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content shadow-lg">
<div class="modal-header border-0 pb-1">
<h6 class="modal-title fw-bold" id="thematicChooserModalLabel">
<i class="bi bi-layers-fill text-primary me-1"></i>{% translate "Choisir une thématique" %}
</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
</div>
<div class="modal-body p-3">
<div class="row g-2" id="thematic-tiles-container">
{% for t in thematics %}
<div class="col-12 col-sm-6">
<div class="thematic-tile d-flex align-items-center gap-3 {% if t.code == 'parking' %}active{% endif %}" data-code="{{ t.code }}" data-icon="{{ t.icon|default:'bi-folder2' }}" data-name="{{ t.name }}" data-bs-dismiss="modal">
<div class="thematic-tile-icon" style="background-color: {{ t.color|default:'#0d6efd' }}15; color: {{ t.color|default:'#0d6efd' }};">
<i class="bi {{ t.icon|default:'bi-folder2' }}"></i>
</div>
<div class="flex-grow-1">
<h6 class="mb-0 fw-bold small text-dark">{{ t.name }}</h6>
<small class="text-muted" style="font-size: 0.75rem;">{{ t.description|default:""|truncatechars:45 }}</small>
</div>
<i class="bi bi-check-circle-fill text-primary fs-5 thematic-check d-none"></i>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
<!-- Modal Choix de Catégorie (Style Mobile Bottom Sheet) -->
<div class="modal fade modal-bottom-sheet" id="categoryChooserModal" tabindex="-1" aria-labelledby="categoryChooserModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content shadow-lg">
<div class="modal-header border-0 pb-1">
<h6 class="modal-title fw-bold" id="categoryChooserModalLabel">
<i class="bi bi-tags-fill text-primary me-1"></i>{% translate "Filtrer par catégorie" %}
</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
</div>
<div class="modal-body p-3">
<div class="list-group list-group-flush" id="category-list-container">
<button type="button" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center py-2.5 px-3 rounded-3 mb-1 border-0 category-item active" data-id="" data-name="{% translate 'Toutes les catégories' %}" data-bs-dismiss="modal">
<span class="fw-semibold small">{% translate "Toutes les catégories" %}</span>
<i class="bi bi-check-lg text-primary category-check"></i>
</button>
{% for c in categories %}
<button type="button" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center py-2.5 px-3 rounded-3 mb-1 border-0 category-item" data-id="{{ c.id }}" data-thematic="{{ c.thematic.code }}" data-name="{{ c.get_name }}" data-bs-dismiss="modal">
<span class="fw-semibold small text-dark">{{ c.get_name }}</span>
<i class="bi bi-check-lg text-primary category-check d-none"></i>
</button>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
<!-- Inclure la Modale d'inspection -->
{% include "assets/components/inspection_form_modal.html" %}
{% endblock %}
{% block footer %}{% endblock %}
{% block extra_js %}
<script src="{% static 'common/layer-switcher-control.js' %}"></script>
<script src="{% static 'common/address_search_control.js' %}"></script>
<script>window.AUTOCOMPLETE_STREET_URL = "{% url 'common:autocomplete_street' %}";</script>
<script src="{% static 'assets/inspection_map.js' %}"></script>
{% endblock %}