Files
awo-hamburg-intranet/module/tasks/assets/js/task_cert_admin_actions.js
Moritz Weinmann 743476f64a Module tasks + knowledgecenter_update aus Kundenprojekt übernehmen (bereinigt)
Beide Module wurden aus einem anderen Kundenprojekt kopiert und bereinigt:

Knowledgecenter:
- Bild-Cache (1.985 Dateien) geleert, Ordnerstruktur mit .gitkeep behalten
- Files-Gallery-Lizenzschlüssel entfernt (config.php)
- Kundenspezifische Kategorien gelöscht: Teil I/II/III QM-Struktur,
  nummerierte QM-Kapitel, Gremien (Präsidium/Finanzausschuss/Landesausschuss),
  Sitzungsservice-Serie, Protokoll-Abteilungen, Testeinträge
- 56 generische Kategorien bleiben (Downloads, Onboarding, Personalthemen …)

Tasks:
- Alle Betriebsdaten gelöscht (114 Tasks, 914 Submissions, 579 Assignments)
- Task-Definitionen und Verlinkungen geleert
- Kategoriestruktur bleibt (Allgemein, IT, Personal, Buchhaltung …)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 09:20:02 +02:00

220 lines
8.7 KiB
JavaScript

(function () {
'use strict';
var root = document.querySelector('.task-cert-admin-monitoring');
if (!root) { return; }
var csrfToken = root.getAttribute('data-csrf-token') || '';
var resetAssignmentUrl = root.getAttribute('data-reset-assignment-url') || '';
var resetCycleUrl = root.getAttribute('data-reset-cycle-url') || '';
var approvalUrl = root.getAttribute('data-approval-url') || '';
var taskId = parseInt(root.getAttribute('data-task-id') || '0', 10);
// ── Toast ─────────────────────────────────────────────────────
var toastContainer = document.getElementById('task-cert-toast-container');
function showToast(message, type) {
if (!toastContainer) { return; }
var cls = type === 'error' ? 'task-cert-error' : 'task-cert-success';
var toast = document.createElement('div');
toast.className = 'task-cert-toast ' + cls;
toast.textContent = String(message || '');
toast.addEventListener('click', function () {
removeToast(toast);
});
toastContainer.appendChild(toast);
// Trigger fade-in on next frame
requestAnimationFrame(function () {
toast.classList.add('is-visible');
});
var autoHideMs = type === 'error' ? 7000 : 4000;
setTimeout(function () {
removeToast(toast);
}, autoHideMs);
}
function removeToast(toast) {
if (!toast || !toast.parentNode) { return; }
toast.classList.remove('is-visible');
setTimeout(function () {
if (toast.parentNode) {
toast.parentNode.removeChild(toast);
}
}, 250);
}
// Expose globally so other admin scripts (mark_completed) can reuse
window.TaskCertAdminActions = window.TaskCertAdminActions || {};
window.TaskCertAdminActions.showToast = showToast;
// ── Fetch-Helper ──────────────────────────────────────────────
function postJson(url, body) {
return fetch(url, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
}).then(function (res) {
return res.json().then(function (data) {
return { ok: res.ok, status: res.status, data: data };
}).catch(function () {
return { ok: false, status: res.status, data: { success: false, error: 'Ungültige Server-Antwort' } };
});
});
}
function reloadWithDelay() {
setTimeout(function () {
location.reload();
}, 800);
}
function setButtonBusy(btn, busy, busyLabel) {
if (!btn) { return; }
if (busy) {
btn._originalLabel = btn.textContent;
btn.textContent = busyLabel || 'Wird verarbeitet...';
btn.disabled = true;
} else {
if (btn._originalLabel) { btn.textContent = btn._originalLabel; }
btn.disabled = false;
}
}
// ── Action: Reset Assignment ──────────────────────────────────
function handleResetAssignment(btn) {
var assignmentId = parseInt(btn.getAttribute('data-assignment-id') || '0', 10);
if (!assignmentId || !taskId || !resetAssignmentUrl) { return; }
if (!window.confirm('Einreichungen und Zertifikat für diesen Zeitraum wirklich zurücksetzen?')) {
return;
}
setButtonBusy(btn, true, 'Wird zurückgesetzt...');
postJson(resetAssignmentUrl, {
csrf_token: csrfToken,
task_id: taskId,
assignment_id: assignmentId
}).then(function (result) {
if (result.data && result.data.success) {
showToast('Zeitraum wurde zurückgesetzt.', 'success');
reloadWithDelay();
} else {
setButtonBusy(btn, false);
showToast((result.data && result.data.error) || 'Fehler beim Zurücksetzen.', 'error');
}
}).catch(function (err) {
setButtonBusy(btn, false);
showToast('Netzwerkfehler: ' + (err && err.message ? err.message : 'Unbekannt'), 'error');
});
}
// ── Action: Reset Cycle ───────────────────────────────────────
function handleResetCycle(btn) {
var btnTaskId = parseInt(btn.getAttribute('data-task-id') || '0', 10) || taskId;
if (!btnTaskId || !resetCycleUrl) { return; }
if (!window.confirm('Wirklich ALLE Einreichungen und Zertifikate im aktuellen Zyklus zurücksetzen? Diese Aktion betrifft alle Mitarbeiter in diesem Zeitraum.')) {
return;
}
setButtonBusy(btn, true, 'Wird zurückgesetzt...');
postJson(resetCycleUrl, {
csrf_token: csrfToken,
task_id: btnTaskId
}).then(function (result) {
if (result.data && result.data.success) {
var stats = (result.data && result.data.stats) || {};
var n = parseInt(stats.assignment_count || 0, 10);
showToast('Zyklus wurde zurückgesetzt (' + n + ' Zuweisungen).', 'success');
reloadWithDelay();
} else {
setButtonBusy(btn, false);
showToast((result.data && result.data.error) || 'Fehler beim Zurücksetzen.', 'error');
}
}).catch(function (err) {
setButtonBusy(btn, false);
showToast('Netzwerkfehler: ' + (err && err.message ? err.message : 'Unbekannt'), 'error');
});
}
// ── Action: Approval ──────────────────────────────────────────
function handleApproval(btn) {
var wrapper = btn.closest('.task-cert-inline-approval-form');
if (!wrapper) { return; }
var submissionId = parseInt(wrapper.getAttribute('data-submission-id') || '0', 10);
var decision = btn.getAttribute('data-decision') || '';
if (!submissionId || !decision || !approvalUrl) { return; }
var noteEl = wrapper.querySelector('.task-cert-approval-note');
var note = noteEl ? noteEl.value.trim() : '';
if (decision === 'reject' && !window.confirm('Einreichung wirklich ablehnen?')) {
return;
}
// Disable both buttons in this row
var siblings = wrapper.querySelectorAll('.task-cert-btn-approval');
for (var i = 0; i < siblings.length; i++) {
siblings[i].disabled = true;
}
setButtonBusy(btn, true, decision === 'approve' ? 'Freigabe...' : 'Ablehnen...');
postJson(approvalUrl, {
csrf_token: csrfToken,
submission_id: submissionId,
decision: decision,
note: note
}).then(function (result) {
if (result.data && result.data.success) {
var msg = decision === 'approve' ? 'Einreichung freigegeben.' : 'Einreichung abgelehnt.';
showToast(msg, 'success');
reloadWithDelay();
} else {
for (var j = 0; j < siblings.length; j++) { siblings[j].disabled = false; }
setButtonBusy(btn, false);
showToast((result.data && result.data.error) || 'Fehler bei der Bearbeitung.', 'error');
}
}).catch(function (err) {
for (var k = 0; k < siblings.length; k++) { siblings[k].disabled = false; }
setButtonBusy(btn, false);
showToast('Netzwerkfehler: ' + (err && err.message ? err.message : 'Unbekannt'), 'error');
});
}
// ── Event-Delegation ──────────────────────────────────────────
document.addEventListener('click', function (e) {
var resetAssignBtn = e.target.closest('.task-cert-btn-reset-assignment');
if (resetAssignBtn) {
e.preventDefault();
handleResetAssignment(resetAssignBtn);
return;
}
var resetCycleBtn = e.target.closest('.task-cert-btn-reset-cycle');
if (resetCycleBtn) {
e.preventDefault();
handleResetCycle(resetCycleBtn);
return;
}
var approvalBtn = e.target.closest('.task-cert-btn-approval');
if (approvalBtn) {
e.preventDefault();
handleApproval(approvalBtn);
return;
}
});
})();