loko/streetup/projects/static/projects/projects_detail.js
2026-07-22 14:48:40 +02:00

801 lines
No EOL
29 KiB
JavaScript

var center = [4.3572, 50.8477];
var zoom = 11;
if (feature_lon && feature_lat) {
center = [feature_lon, feature_lat];
zoom = 17
}
const map = new maplibregl.Map({
style: window.MAP_STYLE_LIGHT,
center: center,
zoom: zoom,
pitch: 45,
bearing: -17.6,
container: 'map',
antialias: true
});
map.on('load', () => {
if (geomGeoJSON && geomGeoJSON.features.length > 0) {
map.addSource('project', {
type: 'geojson',
data: geomGeoJSON
});
map.addLayer({
id: 'project-layer',
type: 'fill',
source: 'project',
paint: {
'fill-color': '#007cbf',
'fill-opacity': 0.5,
'fill-outline-color': '#000'
}
});
// Zoom sur le bounding box du projet
const bounds = new maplibregl.LngLatBounds();
geomGeoJSON.features.forEach(feature => {
const geom = feature.geometry;
if (!geom) return;
const rings = geom.type === 'Polygon' ? geom.coordinates
: geom.type === 'MultiPolygon' ? geom.coordinates.flat(1)
: [];
rings.forEach(ring => ring.forEach(coord => bounds.extend(coord)));
});
if (!bounds.isEmpty()) {
map.fitBounds(bounds, { padding: 40 });
}
}
});
// Initialization after page load
$( document ).ready(function() {
$('.circle.action').on('click', function () {
//alert("Action pour passer au statut " + $(this).attr('status'));
});
});
function showAlert(message, alertContainer, type="success") {
const alertBox = document.createElement("div");
alertBox.className = `alert alert-${type} alert-dismissible fade show`;
alertBox.role = "alert";
alertBox.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
`;
alertContainer.appendChild(alertBox);
// Auto-dismiss after 5 seconds
// setTimeout(() => {
// alertBox.classList.remove("show");
// alertBox.classList.add("hide");
// }, 5000);
}
const addMemberForm = document.getElementById("addMemberForm");
if (addMemberForm) {
addMemberForm.addEventListener("submit", function(e) { e.preventDefault(); submitUserMemberForm(); });
}
function submitAccessForm() {
const teamTabActive = document.getElementById('team-tab')?.classList.contains('active');
if (teamTabActive) {
submitTeamAccessForm();
} else {
submitUserMemberForm();
}
}
function submitUserMemberForm() {
const form = document.getElementById("addMemberForm");
if (!form) return;
const alertContainer = document.getElementById("membersAlertContainer");
const userId = document.getElementById("userAccessUserId").value;
if (!userId) {
showAlert("❌ " + gettext("Veuillez sélectionner un utilisateur."), alertContainer, "danger");
return;
}
const formData = new FormData(form);
fetch(`/projects/${project_id}/add_member/`, {
method: "POST",
headers: {
"X-CSRFToken": form.querySelector('[name=csrfmiddlewaretoken]').value,
},
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert("✅ Membre ajouté !", alertContainer, "success");
resetUserSearch();
form.reset();
const modal = bootstrap.Modal.getInstance(document.getElementById('addMemberModal'));
modal.hide();
const member = data.member;
const container = document.querySelector("#membersContainer");
const wrapper = document.createElement("div");
wrapper.id = `member-container-${member.id}`;
wrapper.className = "border-bottom p-1 d-flex justify-content-between align-items-center";
const roleLabel = member.can_edit ? ` - ${gettext('Éditeur')}` : '';
wrapper.innerHTML = `
<span><i class="bi bi-person me-1"></i>${member.first_name} ${member.last_name}${roleLabel}</span>
<a href="#" class="btn btn-sm btn-outline-secondary border-0" title="Supprimer"
onclick="openDeleteModal(this)"
data-member-id="${member.id}"
data-member-type="user"
data-member-name="${member.first_name} ${member.last_name}${roleLabel}"
data-bs-toggle="modal" data-bs-target="#deleteMemberModal">
<i class="bi bi-trash"></i>
</a>
`;
container.appendChild(wrapper);
} else {
let errorMsg = data.errors ? Object.values(data.errors).flat().join("<br>") : data.error;
showAlert("❌ " + errorMsg, alertContainer, "danger");
}
});
}
function submitTeamAccessForm() {
const form = document.getElementById("addTeamAccessForm");
if (!form) return;
const alertContainer = document.getElementById("membersAlertContainer");
const teamId = document.getElementById("teamAccessTeamId").value;
if (!teamId) {
showAlert("❌ " + gettext("Veuillez sélectionner une équipe."), alertContainer, "danger");
return;
}
const formData = new FormData(form);
fetch(`/projects/${project_id}/add-team-access/`, {
method: "POST",
headers: {
"X-CSRFToken": form.querySelector('[name=csrfmiddlewaretoken]').value,
},
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert("✅ Équipe ajoutée !", alertContainer, "success");
resetTeamSearch();
form.reset();
const modal = bootstrap.Modal.getInstance(document.getElementById('addMemberModal'));
modal.hide();
const ta = data.team_access;
const container = document.querySelector("#membersContainer");
const wrapper = document.createElement("div");
wrapper.id = `team-access-container-${ta.id}`;
wrapper.className = "border-bottom p-1 d-flex justify-content-between align-items-center";
const roleLabel = ta.can_edit ? ` - ${gettext('Éditeur')}` : '';
const displayName = `${ta.team_name} (${ta.team_company})`;
wrapper.innerHTML = `
<span><i class="bi bi-people me-1"></i>${displayName}${roleLabel}</span>
<a href="#" class="btn btn-sm btn-outline-secondary border-0" title="Supprimer"
onclick="openDeleteModal(this)"
data-member-id="${ta.id}"
data-member-type="team"
data-member-name="${displayName}${roleLabel}"
data-bs-toggle="modal" data-bs-target="#deleteMemberModal">
<i class="bi bi-trash"></i>
</a>
`;
container.appendChild(wrapper);
} else {
let errorMsg = data.errors ? Object.values(data.errors).flat().join("<br>") : data.error;
showAlert("❌ " + errorMsg, alertContainer, "danger");
}
});
}
function resetTeamSearch() {
const input = document.getElementById("teamSearchInput");
const results = document.getElementById("teamSearchResults");
const display = document.getElementById("teamSelectedDisplay");
const hiddenId = document.getElementById("teamAccessTeamId");
if (input) input.value = '';
if (results) results.innerHTML = '';
if (display) { display.textContent = ''; display.classList.add('d-none'); }
if (hiddenId) hiddenId.value = '';
}
function resetUserSearch() {
const input = document.getElementById("userSearchInput");
const results = document.getElementById("userSearchResults");
const display = document.getElementById("userSelectedDisplay");
const hiddenId = document.getElementById("userAccessUserId");
if (input) input.value = '';
if (results) results.innerHTML = '';
if (display) { display.textContent = ''; display.classList.add('d-none'); }
if (hiddenId) hiddenId.value = '';
}
function renderUserResults(users) {
const results = document.getElementById("userSearchResults");
if (!results) return;
results.innerHTML = '';
users.slice(0, 20).forEach(u => {
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'list-group-item list-group-item-action py-1 px-2';
btn.textContent = u.text;
btn.addEventListener('click', function () {
document.getElementById("userAccessUserId").value = u.id;
const display = document.getElementById("userSelectedDisplay");
display.textContent = `✔ ${u.text}`;
display.classList.remove('d-none');
document.getElementById("userSearchInput").value = '';
results.innerHTML = '';
});
results.appendChild(btn);
});
}
function fetchUsers(term) {
const url = `${user_search_url}?q=${encodeURIComponent(term)}&project_id=${project_id}`;
fetch(url)
.then(r => r.json())
.then(data => renderUserResults(data.results || []));
}
// Team + User search logic
document.addEventListener('DOMContentLoaded', function () {
// ---- Team search ----
const teamSearchInput = document.getElementById("teamSearchInput");
if (teamSearchInput) {
function renderTeamResults(term) {
const results = document.getElementById("teamSearchResults");
results.innerHTML = '';
const filtered = (typeof allTeams !== 'undefined' ? allTeams : []).filter(t =>
!term || t.name.toLowerCase().includes(term) || t.company.toLowerCase().includes(term)
);
filtered.slice(0, 20).forEach(t => {
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'list-group-item list-group-item-action py-1 px-2';
btn.textContent = `${t.name} (${t.company})`;
btn.addEventListener('click', function () {
document.getElementById("teamAccessTeamId").value = t.id;
const display = document.getElementById("teamSelectedDisplay");
display.textContent = `✔ ${t.name} (${t.company})`;
display.classList.remove('d-none');
teamSearchInput.value = '';
results.innerHTML = '';
});
results.appendChild(btn);
});
}
teamSearchInput.addEventListener('focus', function () { renderTeamResults(this.value.toLowerCase().trim()); });
teamSearchInput.addEventListener('input', function () { renderTeamResults(this.value.toLowerCase().trim()); });
}
// ---- User search ----
const userSearchInput = document.getElementById("userSearchInput");
if (userSearchInput) {
let userSearchTimer = null;
userSearchInput.addEventListener('focus', function () { fetchUsers(this.value.trim()); });
userSearchInput.addEventListener('input', function () {
clearTimeout(userSearchTimer);
const term = this.value.trim();
userSearchTimer = setTimeout(() => fetchUsers(term), 200);
});
}
// Reset both searches when modal is hidden
const addMemberModal = document.getElementById('addMemberModal');
if (addMemberModal) {
addMemberModal.addEventListener('hidden.bs.modal', function () {
resetTeamSearch();
resetUserSearch();
});
}
// Accès strict toggle
const strictAccessToggle = document.getElementById('strictAccessToggle');
if (strictAccessToggle) {
strictAccessToggle.addEventListener('change', function () {
fetch(`/projects/${project_id}/toggle-strict-access/`, {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `strict_access=${this.checked ? 'true' : 'false'}`,
})
.then(r => r.json())
.then(data => {
if (!data.success) {
this.checked = !this.checked;
}
})
.catch(() => { this.checked = !this.checked; });
});
}
});
// Remove Select2 initialisation (replaced by custom search)
let memberToDeleteId = null;
let memberToDeleteType = null;
let memberToDeleteName = null;
let memberDivToDelete = null;
// Quand on clique sur la corbeille
function openDeleteModal(element) {
memberToDeleteId = element.dataset.memberId;
memberToDeleteType = element.dataset.memberType;
memberToDeleteName = element.dataset.memberName;
const prefix = memberToDeleteType === 'team' ? 'team-access-container' : 'member-container';
memberDivToDelete = document.getElementById(`${prefix}-${memberToDeleteId}`);
const memberNameContainer = document.getElementById("memberNameToDeleteContainer");
memberNameContainer.innerHTML = `<strong>${memberToDeleteName}</strong>`;
const modalEl = document.getElementById('deleteMemberModal');
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
modal.show();
}
function deleteMember(element) {
if (!memberToDeleteId) return;
const memberId = memberToDeleteId;
const memberDiv = memberDivToDelete;
const alertContainer = document.getElementById("membersAlertContainer");
const url = memberToDeleteType === 'team'
? `/projects/${project_id}/team-access/${memberId}/delete/`
: `/projects/${project_id}/members/${memberId}/delete/`;
fetch(url, {
method: "POST",
headers: {
"X-CSRFToken": getCookie("csrftoken")
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
memberDiv.remove();
showAlert(`✅ ${gettext("Membre supprimé")} !`, alertContainer, "success");
} else {
showAlert(`❌ ${gettext("Erreur")} : ` + data.error, alertContainer, "danger");
}
// Réinitialiser et fermer la modale
memberToDeleteId = null;
memberToDeleteType = null;
memberDivToDelete = null;
//const memberNameContainer = document.getElementById("memberNameToDeleteContainer");
//memberNameContainer.innerHTML = '';
const modal = bootstrap.Modal.getInstance(document.getElementById('deleteMemberModal'));
if (modal) modal.hide();
});
}
$(document).ready(function () {
// Event listener pour les boutons de dissociation de commandes
$(document).on('click', '.dissociate-order-btn', function(e) {
e.preventDefault();
openDissociateOrderModal(this);
});
// Initialisation de Select2 pour le champ de sélection des commandes
$('#id_order_select').select2({
dropdownParent: $('#associateOrderModal'),
theme: 'bootstrap-5',
placeholder: gettext('Rechercher une commande...'),
allowClear: true,
width: '100%'
});
// Event listener pour les boutons de suppression de phases
$(document).on('click', '.delete-phase-btn', function(e) {
e.preventDefault();
openDeletePhaseModal(this);
});
// Event listener pour confirmer la suppression de phase
$('#confirmDeletePhaseBtn').on('click', function() {
deletePhase();
});
});
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
// Gestion de la dissociation de commandes
let orderToDissociateId = null;
let orderToDissociateCode = null;
function openDissociateOrderModal(element) {
orderToDissociateId = element.dataset.orderId;
orderToDissociateCode = element.dataset.orderCode;
const orderCodeContainer = document.getElementById("orderCodeToDissociateContainer");
orderCodeContainer.innerHTML = `<strong>${orderToDissociateCode}</strong>`;
const modalEl = document.getElementById('dissociateOrderModal');
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
modal.show();
}
function dissociateOrder() {
if (!orderToDissociateId) return;
const orderId = orderToDissociateId;
fetch(`/projects/${project_id}/dissociate-order/${orderId}/`, {
method: "POST",
headers: {
"X-CSRFToken": getCookie("csrftoken")
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Recharger la page pour afficher les changements
location.reload();
} else {
alert(`${gettext("Erreur")} : ` + data.error);
}
// Réinitialiser et fermer la modale
orderToDissociateId = null;
const modal = bootstrap.Modal.getInstance(document.getElementById('dissociateOrderModal'));
if (modal) modal.hide();
});
}
// Gestion de la suppression de phases
let phaseToDeleteId = null;
let phaseToDeleteName = null;
function openDeletePhaseModal(element) {
phaseToDeleteId = element.dataset.phaseId;
phaseToDeleteName = element.dataset.phaseName;
const phaseNameContainer = document.getElementById("phaseNameToDeleteContainer");
phaseNameContainer.innerHTML = `<strong>${phaseToDeleteName}</strong>`;
const modalEl = document.getElementById('deletePhaseModal');
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
modal.show();
}
function deletePhase() {
if (!phaseToDeleteId) return;
const phaseId = phaseToDeleteId;
fetch(`/projects/${project_id}/phases/${phaseId}/delete/`, {
method: "POST",
headers: {
"X-CSRFToken": getCookie("csrftoken")
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Supprimer l'élément du DOM
const phaseContainer = document.getElementById(`phase-container-${phaseId}`);
if (phaseContainer) {
phaseContainer.remove();
}
// Fermer la modale
const modal = bootstrap.Modal.getInstance(document.getElementById('deletePhaseModal'));
if (modal) modal.hide();
// Recharger la page pour mettre à jour l'affichage
location.reload();
} else {
alert(`${gettext("Erreur")} : ` + (data.error || gettext("Une erreur est survenue")));
}
// Réinitialiser
phaseToDeleteId = null;
phaseToDeleteName = null;
})
.catch(error => {
alert(`${gettext("Erreur")} : ` + error);
phaseToDeleteId = null;
phaseToDeleteName = null;
});
}
// ─── Document management (add form with tags + history modal) ───────────────
const docFileInput = document.getElementById('docFileInput');
const docFileContainer = document.getElementById('docFileFieldsContainer');
// Runtime config loaded via API
let docConfig = { use_managed_documents: false, can_add_unique_tag_documents: false, config_url: null };
let docAvailableTags = [];
let docAvailableFolders = [];
(function loadDocConfig() {
try {
const el = document.getElementById('projectDocumentConfigData');
if (el) { docConfig = JSON.parse(el.textContent); }
} catch (e) {}
if (!docConfig.config_url) return;
fetch(docConfig.config_url)
.then(r => r.json())
.then(data => {
docConfig.use_managed_documents = data.use_managed_documents;
docConfig.can_add_unique_tag_documents = data.can_add_unique_tag_documents;
docAvailableTags = data.tags || [];
docAvailableFolders = data.folders || [];
})
.catch(() => {});
})();
function renderDocFileFields() {
if (!docFileContainer || !docFileInput) return;
docFileContainer.innerHTML = '';
const files = Array.from(docFileInput.files);
files.forEach((file, index) => {
const row = document.createElement('div');
row.classList.add('d-flex', 'align-items-center', 'gap-3', 'mb-2', 'p-2', 'border', 'rounded');
// File name (read-only label)
const fileName = document.createElement('span');
fileName.classList.add('flex-grow-1', 'text-truncate');
fileName.style.maxWidth = '220px';
fileName.textContent = file.name;
fileName.title = file.name;
row.appendChild(fileName);
if (docConfig.use_managed_documents && docAvailableTags.length > 0) {
// ── Tag select ──
const tagSel = document.createElement('select');
tagSel.name = `tag_${index}`;
tagSel.classList.add('form-select', 'w-auto');
tagSel.style.minWidth = '160px';
const def = document.createElement('option');
def.value = '';
def.textContent = gettext('-- Sans tag --');
tagSel.appendChild(def);
docAvailableTags.forEach(tag => {
const opt = document.createElement('option');
opt.value = tag.slug;
opt.textContent = tag.name;
opt.dataset.isUnique = tag.is_unique;
if (tag.is_unique && !docConfig.can_add_unique_tag_documents) {
opt.disabled = true;
opt.textContent += ' (non autorisé)';
}
tagSel.appendChild(opt);
});
row.appendChild(tagSel);
// ── Folder select (non-unique tags only) ──
const folderSel = document.createElement('select');
folderSel.name = `folder_${index}`;
folderSel.classList.add('form-select', 'w-auto', 'd-none');
folderSel.style.minWidth = '180px';
docAvailableFolders.forEach(folder => {
const opt = document.createElement('option');
opt.value = folder.id;
opt.textContent = folder.path;
if (folder.is_root) opt.selected = true;
folderSel.appendChild(opt);
});
row.appendChild(folderSel);
tagSel.addEventListener('change', function () {
const selOpt = tagSel.options[tagSel.selectedIndex];
const isUniq = selOpt.dataset.isUnique === 'true' || selOpt.dataset.isUnique === 'True';
if (!isUniq && tagSel.value) {
folderSel.classList.remove('d-none');
} else {
folderSel.classList.add('d-none');
}
});
} else {
// ── Legacy: hidden input keeps count consistent ──
const hidden = document.createElement('input');
hidden.type = 'hidden';
hidden.name = `document_type_${index}`;
hidden.value = 'other';
row.appendChild(hidden);
}
// ── Remove button ──
const delBtn = document.createElement('button');
delBtn.type = 'button';
delBtn.classList.add('btn', 'btn-outline-danger', 'btn-sm');
delBtn.innerHTML = '<i class="bi bi-x-lg"></i>';
delBtn.onclick = () => {
const remaining = Array.from(docFileInput.files).filter((_, i) => i !== index);
const dt = new DataTransfer();
remaining.forEach(f => dt.items.add(f));
docFileInput.files = dt.files;
renderDocFileFields();
};
row.appendChild(delBtn);
docFileContainer.appendChild(row);
});
// hidden file_count
const countInput = document.createElement('input');
countInput.type = 'hidden';
countInput.name = 'file_count';
countInput.value = files.length;
docFileContainer.appendChild(countInput);
}
if (docFileInput) {
docFileInput.addEventListener('change', renderDocFileFields);
}
// ── Document history modal ────────────────────────────────────────────────────
const docHistoryModalEl = document.getElementById('documentHistoryModal');
if (docHistoryModalEl) {
docHistoryModalEl.addEventListener('show.bs.modal', function (event) {
const btn = event.relatedTarget;
const tagSlug = btn.getAttribute('data-tag-slug');
const locationId = btn.getAttribute('data-location-id');
const useManaged = btn.getAttribute('data-use-managed') === 'true';
const uniqueParams = btn.getAttribute('data-unique-params');
const contentEl = document.getElementById('documentHistoryContent');
if (contentEl) {
contentEl.innerHTML = '<div class="text-center py-4"><div class="spinner-border text-primary" role="status"></div></div>';
}
if (!useManaged || !tagSlug) return;
let url = `${document_history_url}?tag_slug=${encodeURIComponent(tagSlug)}`;
if (uniqueParams && uniqueParams !== '{}' && uniqueParams !== 'null') {
url += `&unique_params=${encodeURIComponent(uniqueParams)}`;
}
fetch(url)
.then(r => r.json())
.then(data => {
if (contentEl) contentEl.innerHTML = data.html || '';
})
.catch(() => {
if (contentEl) contentEl.innerHTML = '<p class="text-muted">Impossible de charger l\'historique.</p>';
});
});
}
// ─── End document management ─────────────────────────────────────────────────
// Gestion de la suppression de documents
document.addEventListener('DOMContentLoaded', function () {
const documentsContainer = document.getElementById('documentsContainer');
const deleteDocumentModalEl = document.getElementById('deleteDocumentModal');
const confirmDeleteBtn = document.getElementById('confirmDeleteDocument');
const documentsAlertContainer = document.getElementById('documentsAlertContainer');
if (!documentsContainer || !deleteDocumentModalEl || !confirmDeleteBtn) {
return;
}
const modal = bootstrap.Modal.getOrCreateInstance(deleteDocumentModalEl);
const documentNameContainer = document.getElementById('documentNameToDelete');
const successDeleteDocumentMsg = typeof gettext !== 'undefined' ? gettext('Document supprimé !') : 'Document supprimé !';
const errorDeleteDocumentMsg = typeof gettext !== 'undefined' ? gettext('Une erreur est survenue lors de la suppression du document.') : 'Une erreur est survenue lors de la suppression du document.';
let documentIdToDelete = null;
let documentCardToDelete = null;
documentsContainer.addEventListener('click', (event) => {
const deleteBtn = event.target.closest('.delete-document-btn');
if (!deleteBtn) {
return;
}
documentIdToDelete = deleteBtn.dataset.documentId || null;
documentCardToDelete = documentIdToDelete ? document.getElementById(`document-card-${documentIdToDelete}`) : null;
if (documentNameContainer) {
documentNameContainer.textContent = deleteBtn.dataset.documentName || '';
}
modal.show();
});
deleteDocumentModalEl.addEventListener('hidden.bs.modal', () => {
documentIdToDelete = null;
documentCardToDelete = null;
confirmDeleteBtn.disabled = false;
if (documentNameContainer) {
documentNameContainer.textContent = '';
}
});
confirmDeleteBtn.addEventListener('click', () => {
if (!documentIdToDelete) {
return;
}
confirmDeleteBtn.disabled = true;
fetch(`/projects/${project_id}/documents/${documentIdToDelete}/delete/`, {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'X-Requested-With': 'XMLHttpRequest',
},
})
.then(response => response.json().then(data => ({ ok: response.ok, data })))
.then(({ ok, data }) => {
if (ok && data.success) {
if (documentCardToDelete) {
documentCardToDelete.remove();
}
if (documentsAlertContainer) {
showAlert(`✅ ${successDeleteDocumentMsg}`, documentsAlertContainer, 'success');
}
} else {
if (documentsAlertContainer) {
const errorMsg = data && data.error ? data.error : errorDeleteDocumentMsg;
showAlert(`❌ ${errorMsg}`, documentsAlertContainer, 'danger');
}
}
})
.catch(() => {
if (documentsAlertContainer) {
showAlert(`❌ ${errorDeleteDocumentMsg}`, documentsAlertContainer, 'danger');
}
})
.finally(() => {
confirmDeleteBtn.disabled = false;
modal.hide();
});
});
});