loko/streetup/home/templates/home/_add_repair_intervention_modal.html
2026-07-22 14:48:40 +02:00

329 lines
14 KiB
HTML

{% load i18n %}
<!-- Modal for adding repair intervention (structures only) -->
<div class="modal fade" id="addRepairInterventionModal" tabindex="-1" aria-labelledby="addRepairInterventionModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addRepairInterventionModalLabel">{% translate "Nouvelle intervention de réparation" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
</div>
<div class="modal-body">
<form id="addRepairInterventionForm">
{% csrf_token %}
<!-- Localisation -->
<div class="mb-3">
<label for="locationSearchDesktop" class="form-label required">{% translate "Localisation" %}</label>
<input type="text"
class="form-control"
id="locationSearchDesktop"
placeholder="{% translate 'Rechercher une localisation...' %}"
autocomplete="off">
<div id="locationResultsDesktop" class="border rounded mt-1 p-2" style="max-height: 250px; overflow-y: auto; display: none;">
</div>
<div id="selectedLocationDesktop" class="alert alert-info mt-2" style="display: none;">
<span id="selectedLocationTextDesktop"></span>
<button type="button" class="btn btn-sm btn-outline-danger float-end" onclick="clearLocationDesktop()">
<i class="bi bi-x-lg"></i>
</button>
</div>
<input type="hidden" name="location_id" id="locationIdDesktop" value="">
</div>
<!-- Catégorie -->
<div class="mb-3">
<label for="categorySelectDesktop" class="form-label required">{% translate "Catégorie" %}</label>
<select class="form-select" name="category_id" id="categorySelectDesktop" required>
<option value="">{% translate "Sélectionner une catégorie" %}</option>
{% for category in categories %}
<option value="{{ category.id }}">{{ category.get_name }}</option>
{% endfor %}
</select>
</div>
<!-- Équipement (optionnel) -->
<div class="mb-3">
<label for="assetSearchDesktop" class="form-label">{% translate "Équipement" %} <small class="text-muted">({% translate "optionnel" %})</small></label>
<input type="text"
class="form-control"
id="assetSearchDesktop"
placeholder="{% translate 'Rechercher un équipement...' %}"
autocomplete="off"
disabled>
<small class="text-muted" id="assetSearchHintDesktop">{% translate "Sélectionnez d'abord une localisation" %}</small>
<div id="assetResultsDesktop" class="border rounded mt-1 p-2" style="max-height: 250px; overflow-y: auto; display: none;">
</div>
<div id="selectedAssetDesktop" class="alert alert-info mt-2" style="display: none;">
<span id="selectedAssetTextDesktop"></span>
<button type="button" class="btn btn-sm btn-outline-danger float-end" onclick="clearAssetDesktop()">
<i class="bi bi-x-lg"></i>
</button>
</div>
<input type="hidden" name="asset_id" id="assetIdDesktop" value="">
</div>
<!-- Titre -->
<div class="mb-3">
<label for="titleInputDesktop" class="form-label required">{% translate "Titre" %}</label>
<input type="text"
class="form-control"
name="title"
id="titleInputDesktop"
placeholder="{% translate 'Titre de l\'intervention' %}"
required>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
<button type="button" class="btn btn-success" onclick="submitRepairInterventionForm()">
<i class="bi bi-check-lg me-2"></i>{% translate "Créer l'intervention" %}
</button>
</div>
</div>
</div>
</div>
<script>
(function() {
const locationSearch = document.getElementById('locationSearchDesktop');
const locationResults = document.getElementById('locationResultsDesktop');
const locationId = document.getElementById('locationIdDesktop');
const selectedLocation = document.getElementById('selectedLocationDesktop');
const selectedLocationText = document.getElementById('selectedLocationTextDesktop');
const assetSearch = document.getElementById('assetSearchDesktop');
const assetResults = document.getElementById('assetResultsDesktop');
const assetId = document.getElementById('assetIdDesktop');
const selectedAsset = document.getElementById('selectedAssetDesktop');
const selectedAssetText = document.getElementById('selectedAssetTextDesktop');
const assetSearchHint = document.getElementById('assetSearchHintDesktop');
const categorySelect = document.getElementById('categorySelectDesktop');
const titleInput = document.getElementById('titleInputDesktop');
let searchTimeout = null;
// Location search
locationSearch.addEventListener('input', function() {
clearTimeout(searchTimeout);
const query = this.value.trim();
if (query.length < 2) {
locationResults.style.display = 'none';
return;
}
searchTimeout = setTimeout(() => {
searchLocations(query);
}, 300);
});
async function searchLocations(query) {
try {
const response = await fetch(`{% url 'assets:locations_autocomplete' %}?q=${encodeURIComponent(query)}&thematic=structures`);
const data = await response.json();
locationResults.innerHTML = '';
if (data.length > 0) {
data.forEach(item => {
const div = document.createElement('div');
div.className = 'p-2 border-bottom cursor-pointer';
div.style.cursor = 'pointer';
div.innerHTML = `<strong>${item.code}</strong> - ${item.name}`;
div.addEventListener('click', () => selectLocationDesktop(item.value.obj, item.code, item.name));
locationResults.appendChild(div);
});
locationResults.style.display = 'block';
} else {
locationResults.innerHTML = '<div class="p-2 text-muted">{% translate "Aucun résultat" %}</div>';
locationResults.style.display = 'block';
}
} catch (error) {
console.error('Error searching locations:', error);
}
}
window.selectLocationDesktop = function(objId, code, name) {
locationId.value = objId;
selectedLocationText.textContent = `${code} - ${name}`;
selectedLocation.style.display = 'block';
locationSearch.value = '';
locationResults.style.display = 'none';
// Enable asset search
assetSearch.disabled = false;
assetSearchHint.style.display = 'none';
// Update title suggestion
updateTitleSuggestionDesktop();
};
window.clearLocationDesktop = function() {
locationId.value = '';
selectedLocation.style.display = 'none';
selectedLocationText.textContent = '';
// Clear and disable asset search
clearAssetDesktop();
assetSearch.disabled = true;
assetSearchHint.style.display = 'block';
};
// Asset search
assetSearch.addEventListener('input', function() {
clearTimeout(searchTimeout);
const query = this.value.trim();
if (query.length < 2 || !locationId.value) {
assetResults.style.display = 'none';
return;
}
searchTimeout = setTimeout(() => {
searchAssets(query);
}, 300);
});
async function searchAssets(query) {
try {
const categoryId = categorySelect.value;
let url = `{% url 'assets:structures_autocomplete_assets' %}?q=${encodeURIComponent(query)}&location_id=${locationId.value}`;
if (categoryId) {
url += `&asset_category=${categoryId}`;
}
const response = await fetch(url);
const data = await response.json();
assetResults.innerHTML = '';
if (data.length > 0) {
data.forEach(item => {
const div = document.createElement('div');
div.className = 'p-2 border-bottom cursor-pointer';
div.style.cursor = 'pointer';
div.innerHTML = item.label;
div.addEventListener('click', () => selectAssetDesktop(item.id, item.label));
assetResults.appendChild(div);
});
assetResults.style.display = 'block';
} else {
assetResults.innerHTML = '<div class="p-2 text-muted">{% translate "Aucun résultat" %}</div>';
assetResults.style.display = 'block';
}
} catch (error) {
console.error('Error searching assets:', error);
}
}
window.selectAssetDesktop = function(id, label) {
assetId.value = id;
selectedAssetText.textContent = label;
selectedAsset.style.display = 'block';
assetSearch.value = '';
assetResults.style.display = 'none';
// Update title suggestion with asset
updateTitleSuggestionDesktop();
};
window.clearAssetDesktop = function() {
assetId.value = '';
selectedAsset.style.display = 'none';
selectedAssetText.textContent = '';
};
// Title suggestion
function updateTitleSuggestionDesktop() {
if (titleInput.value.trim() === '') {
let suggestion = '';
const categoryText = categorySelect.options[categorySelect.selectedIndex]?.text;
const locationText = selectedLocationText.textContent;
if (categoryText && categoryText !== categorySelect.options[0].text) {
suggestion = categoryText;
}
if (locationText) {
const locationCode = locationText.split(' - ')[0];
suggestion = suggestion ? `${suggestion} - ${locationCode}` : locationCode;
}
if (suggestion) {
titleInput.value = suggestion;
}
}
}
categorySelect.addEventListener('change', updateTitleSuggestionDesktop);
// Close results on click outside
document.addEventListener('click', function(e) {
if (!locationSearch.contains(e.target) && !locationResults.contains(e.target)) {
locationResults.style.display = 'none';
}
if (!assetSearch.contains(e.target) && !assetResults.contains(e.target)) {
assetResults.style.display = 'none';
}
});
})();
async function submitRepairInterventionForm() {
const form = document.getElementById('addRepairInterventionForm');
const formData = new FormData(form);
// Validation basique
const locationId = document.getElementById('locationIdDesktop').value;
const categoryId = document.getElementById('categorySelectDesktop').value;
const title = document.getElementById('titleInputDesktop').value.trim();
if (!locationId) {
alert('{% translate "La localisation est obligatoire." %}');
return;
}
if (!categoryId) {
alert('{% translate "La catégorie est obligatoire." %}');
return;
}
if (!title) {
alert('{% translate "Le titre est obligatoire." %}');
return;
}
try {
const response = await fetch('{% url "interventions:add_repair_intervention_modal" %}', {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const data = await response.json();
if (data.success) {
// Close modal
const modal = bootstrap.Modal.getInstance(document.getElementById('addRepairInterventionModal'));
modal.hide();
// Show success message
alert(`{% translate "L'intervention" %} ${data.code} {% translate "a été créée avec succès." %}`);
// Reload page or redirect
window.location.href = '{% url "interventions:interventions_index" %}';
} else {
alert(data.error || '{% translate "Une erreur est survenue." %}');
}
} else {
alert('{% translate "Une erreur est survenue." %}');
}
} catch (error) {
console.error('Error:', error);
alert('{% translate "Une erreur est survenue." %}');
}
}
</script>