145 lines
4.7 KiB
JavaScript
145 lines
4.7 KiB
JavaScript
|
|
const statusTimeline = document.getElementById("statusTimeline");
|
|
|
|
// Récupère la liste des statuts autorisés (inline script ou propriété globale)
|
|
const allowedStatusList = Array.isArray(window.allowedStatuses)
|
|
? window.allowedStatuses
|
|
: (typeof allowedStatuses !== 'undefined' && Array.isArray(allowedStatuses) ? allowedStatuses : []);
|
|
|
|
// Helper CSRF sans redéclarer l'identifiant global s'il existe déjà
|
|
const getCsrfCookie = (typeof window.getCookie === 'function') ? window.getCookie : function(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();
|
|
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return cookieValue;
|
|
};
|
|
|
|
let currentIndex = -1;
|
|
|
|
STATUS_CHOICES.forEach((status, index) => {
|
|
if (status.key === currentStatus) {
|
|
currentIndex = index;
|
|
}
|
|
});
|
|
|
|
let nextActionsIndex = [];
|
|
let pastActionsIndex = [];
|
|
|
|
if (!['closed', 'canceled'].includes(currentStatus)) {
|
|
nextActionsIndex.push(currentIndex + 1);
|
|
}
|
|
|
|
// Annulation accessible tant que le projet n'est pas clôturé/comptabilisé
|
|
if (!['finished', 'invoiced', 'closed', 'canceled'].includes(currentStatus)) {
|
|
const canceledIndex = STATUS_CHOICES.findIndex(status => status.key === 'canceled');
|
|
if (canceledIndex !== -1) {
|
|
nextActionsIndex.push(canceledIndex);
|
|
}
|
|
}
|
|
|
|
STATUS_CHOICES.forEach((status, index) => {
|
|
let statusClass = "hide";
|
|
let actionClass = "";
|
|
let dashedClass = "";
|
|
let buttonClass = "";
|
|
let label = status.label;
|
|
let icon = "";
|
|
const isAllowed = allowedStatusList.includes(status.key);
|
|
|
|
if (index === currentIndex) {
|
|
statusClass = "current";
|
|
dashedClass = "next-step-dashed";
|
|
} else if (index < currentIndex) {
|
|
statusClass = "past";
|
|
if (pastActionsIndex.includes(index) && isAllowed) {
|
|
actionClass = "action";
|
|
buttonClass = "button";
|
|
icon = "bi-arrow-left";
|
|
} else {
|
|
label = "";
|
|
}
|
|
} else if (nextActionsIndex.includes(index)) {
|
|
statusClass = "next";
|
|
if (isAllowed) {
|
|
actionClass = "action";
|
|
buttonClass = "button";
|
|
dashedClass = "next-step-dashed";
|
|
icon = "bi-arrow-right";
|
|
}
|
|
}
|
|
|
|
if (index === (STATUS_CHOICES.length - 1)) {
|
|
dashedClass = "";
|
|
}
|
|
|
|
if (statusClass !== "hide") {
|
|
const step = document.createElement("div");
|
|
step.className = `step ${statusClass} ${dashedClass}`;
|
|
step.innerHTML = `
|
|
<div id="status_${status.key}" status="${status.key}" data-status="${status.key}" class="circle ${actionClass} ${buttonClass} ${status.key}">
|
|
${icon ? '<i class="bi '+icon+'"></i>' : (index + 1)}
|
|
</div>
|
|
<div class="steplabel">${label}</div>
|
|
`;
|
|
statusTimeline.appendChild(step);
|
|
}
|
|
});
|
|
|
|
document.addEventListener('click', (event) => {
|
|
const actionTarget = event.target.closest('.circle.action');
|
|
|
|
if (!actionTarget) {
|
|
return;
|
|
}
|
|
|
|
const newStatus = actionTarget.getAttribute('data-status') || actionTarget.getAttribute('status');
|
|
if (!newStatus) {
|
|
return;
|
|
}
|
|
|
|
if (newStatus === 'canceled') {
|
|
const confirmCancel = typeof gettext === 'function'
|
|
? gettext("Êtes-vous sûr de vouloir annuler ce projet ?")
|
|
: "Êtes-vous sûr de vouloir annuler ce projet ?";
|
|
if (!window.confirm(confirmCancel)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
updateStatus(newStatus);
|
|
});
|
|
|
|
function updateStatus(newStatus) {
|
|
const errorMsg = typeof gettext === 'function'
|
|
? gettext("Erreur lors de la mise à jour du statut.")
|
|
: "Erreur lors de la mise à jour du statut.";
|
|
|
|
fetch(`/projects/${project_id}/update-status/`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'X-CSRFToken': getCsrfCookie('csrftoken'),
|
|
'X-Requested-With': 'XMLHttpRequest',
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: new URLSearchParams({ new_status: newStatus }),
|
|
})
|
|
.then(response => response.json().then(data => ({ ok: response.ok, data })))
|
|
.then(({ ok, data }) => {
|
|
if (ok && data && data.success) {
|
|
window.location.reload();
|
|
return;
|
|
}
|
|
|
|
const message = data && data.message ? data.message : errorMsg;
|
|
window.alert(message);
|
|
})
|
|
.catch(() => window.alert(errorMsg));
|
|
}
|