Files
awo-hamburg-intranet/module/tasks/assets/js/task_cert_admin_mark_completed.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

293 lines
12 KiB
JavaScript

(function () {
'use strict';
var dialog = document.getElementById('task-cert-mark-completed-dialog');
var config = document.getElementById('task-cert-mark-completed-config');
if (!dialog || !config) { return; }
var methodsUrl = config.getAttribute('data-methods-url') || '';
var submitUrl = config.getAttribute('data-submit-url') || '';
var taskId = parseInt(config.getAttribute('data-task-id') || '0', 10);
if (!methodsUrl || !submitUrl || !taskId) { return; }
var METHOD_LABELS = {
knowledge_read: 'Wissensbestätigung',
form_submit: 'Formular',
quiz: 'Quiz',
manual_approval: 'Manuelle Freigabe'
};
function esc(str) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(String(str == null ? '' : str)));
return div.innerHTML;
}
function buildMethodHtml(method) {
var id = method.id;
var type = method.method_type;
var label = METHOD_LABELS[type] || type;
var required = method.is_required ? '' : ' <span class="task-cert-hint">(optional)</span>';
var fulfilled = method.already_fulfilled;
var html = '<fieldset class="task-cert-dialog-method' + (fulfilled ? ' is-fulfilled' : '') + '">';
html += '<legend>' + esc(label) + required;
if (fulfilled) {
html += ' <span class="task-cert-admin-fulfilled-badge">Bereits erledigt</span>';
}
html += '</legend>';
if (fulfilled) {
html += '<p class="task-cert-hint">Wird übersprungen.</p>';
} else if (type === 'knowledge_read') {
html += '<p class="task-cert-hint">Alle ' + method.knowledge_post_count + ' Beiträge werden automatisch als gelesen markiert.</p>';
} else if (type === 'quiz') {
html += '<p class="task-cert-hint">Quiz wird automatisch als bestanden gewertet (' + method.quiz_question_count + ' Fragen, volle Punktzahl).</p>';
} else if (type === 'manual_approval') {
html += '<p class="task-cert-hint">Manuelle Freigabe wird automatisch erteilt.</p>';
} else if (type === 'form_submit') {
var fields = method.form_fields || [];
if (fields.length === 0) {
html += '<p class="task-cert-hint">Keine Formularfelder definiert.</p>';
} else {
html += '<div class="task-cert-dialog-fields">';
for (var i = 0; i < fields.length; i++) {
html += buildFieldHtml(id, fields[i]);
}
html += '</div>';
}
}
html += '</fieldset>';
return html;
}
function buildFieldHtml(methodId, field) {
var key = field.field_key;
var label = field.label || key;
var type = field.field_type;
var req = field.is_required ? ' <span class="task-cert-hint">(Pflicht)</span>' : '';
var placeholder = esc(field.placeholder || '');
var name = 'method__' + methodId + '__' + key;
var inputId = 'mc-field-' + methodId + '-' + key;
var html = '<div class="task-cert-dialog-field">';
html += '<label for="' + inputId + '">' + esc(label) + req + '</label>';
if (type === 'textarea') {
html += '<textarea name="' + name + '" id="' + inputId + '" rows="3" placeholder="' + placeholder + '"></textarea>';
} else if (type === 'select' && field.options.length > 0) {
html += '<select name="' + name + '" id="' + inputId + '">';
html += '<option value="">-- Bitte wählen --</option>';
for (var i = 0; i < field.options.length; i++) {
html += '<option value="' + esc(field.options[i].value) + '">' + esc(field.options[i].label) + '</option>';
}
html += '</select>';
} else if (type === 'checkbox' && field.options.length > 0) {
html += '<div class="task-cert-dialog-checkbox-group">';
for (var j = 0; j < field.options.length; j++) {
html += '<label class="task-cert-dialog-check-label"><input type="checkbox" name="' + name + '[]" value="' + esc(field.options[j].value) + '"> ' + esc(field.options[j].label) + '</label>';
}
html += '</div>';
} else if (type === 'radio' && field.options.length > 0) {
html += '<div class="task-cert-dialog-radio-group">';
for (var k = 0; k < field.options.length; k++) {
html += '<label class="task-cert-dialog-check-label"><input type="radio" name="' + name + '" value="' + esc(field.options[k].value) + '"> ' + esc(field.options[k].label) + '</label>';
}
html += '</div>';
} else {
var inputType = type === 'number' ? 'number' : (type === 'date' ? 'date' : 'text');
html += '<input type="' + inputType + '" name="' + name + '" id="' + inputId + '" placeholder="' + placeholder + '">';
}
html += '</div>';
return html;
}
function buildDialogContent(data) {
var html = '<div class="task-cert-dialog-inner">';
html += '<div class="task-cert-dialog-header">';
html += '<h3>Als erledigt markieren</h3>';
html += '<button type="button" class="task-cert-dialog-close" aria-label="Schließen">&times;</button>';
html += '</div>';
html += '<div class="task-cert-dialog-info">';
html += '<table class="task-cert-info-table">';
html += '<tr><th>Aufgabe</th><td>' + esc(data.task_title) + '</td></tr>';
html += '<tr><th>Mitarbeiter</th><td>' + esc(data.contact_name);
if (data.contact_email) { html += ' <span class="task-cert-hint">(' + esc(data.contact_email) + ')</span>'; }
html += '</td></tr>';
html += '<tr><th>Zyklus</th><td>' + esc(data.cycle_key) + '</td></tr>';
html += '</table>';
html += '</div>';
html += '<form id="task-cert-mark-completed-form">';
html += '<input type="hidden" name="csrf_token" value="' + esc(data.csrf_token) + '">';
if (data.methods && data.methods.length > 0) {
html += '<div class="task-cert-dialog-methods">';
html += '<h4>Methoden</h4>';
html += '<p class="task-cert-hint">Einreichungen werden automatisch erstellt. Bei Formularen können Sie optional Antworten hinterlegen.</p>';
for (var i = 0; i < data.methods.length; i++) {
html += buildMethodHtml(data.methods[i]);
}
html += '</div>';
}
html += '<div class="task-cert-dialog-note">';
html += '<h4>Admin-Notiz</h4>';
html += '<textarea name="admin_note" rows="2" placeholder="Optionale Begründung (wird im Änderungsprotokoll gespeichert)"></textarea>';
html += '</div>';
html += '<div class="task-cert-dialog-actions">';
html += '<button type="button" class="btn task-cert-dialog-cancel">Abbrechen</button>';
html += '<button type="submit" class="btn task-cert-btn-success">Als erledigt markieren</button>';
html += '</div>';
html += '<div id="task-cert-dialog-error" class="task-cert-error" hidden></div>';
html += '</form>';
html += '</div>';
return html;
}
function collectFormData(data) {
var form = document.getElementById('task-cert-mark-completed-form');
if (!form) { return null; }
var adminNote = (form.querySelector('[name="admin_note"]') || {}).value || '';
var csrfToken = (form.querySelector('[name="csrf_token"]') || {}).value || '';
var methodPayloads = {};
var methods = data.methods || [];
for (var i = 0; i < methods.length; i++) {
var m = methods[i];
if (m.already_fulfilled || m.method_type !== 'form_submit') { continue; }
var fields = m.form_fields || [];
var payload = {};
for (var j = 0; j < fields.length; j++) {
var key = fields[j].field_key;
var name = 'method__' + m.id + '__' + key;
if (fields[j].field_type === 'checkbox') {
var checked = form.querySelectorAll('[name="' + name + '[]"]:checked');
var vals = [];
for (var k = 0; k < checked.length; k++) { vals.push(checked[k].value); }
payload[key] = vals;
} else {
var el = form.querySelector('[name="' + name + '"]');
payload[key] = el ? el.value : '';
}
}
methodPayloads[m.id] = payload;
}
return {
csrf_token: csrfToken,
task_id: taskId,
assignment_id: data.assignment_id,
admin_note: adminNote,
method: methodPayloads
};
}
function showError(msg) {
var errEl = document.getElementById('task-cert-dialog-error');
if (errEl) {
errEl.textContent = msg;
errEl.hidden = false;
}
}
function setLoading(on) {
var btn = dialog.querySelector('[type="submit"]');
if (btn) {
btn.disabled = on;
btn.textContent = on ? 'Wird gespeichert...' : 'Als erledigt markieren';
}
}
var currentData = null;
function openDialog(assignmentId) {
dialog.innerHTML = '<div class="task-cert-dialog-inner"><p>Daten werden geladen...</p></div>';
dialog.showModal();
fetch(methodsUrl + '?assignment_id=' + assignmentId, { credentials: 'same-origin' })
.then(function (res) { return res.json(); })
.then(function (data) {
if (data.error) {
dialog.innerHTML = '<div class="task-cert-dialog-inner"><div class="task-cert-error">' + esc(data.error) + '</div><div class="task-cert-dialog-actions"><button type="button" class="btn task-cert-dialog-cancel">Schließen</button></div></div>';
return;
}
currentData = data;
dialog.innerHTML = buildDialogContent(data);
})
.catch(function (err) {
dialog.innerHTML = '<div class="task-cert-dialog-inner"><div class="task-cert-error">Fehler: ' + esc(err.message) + '</div><div class="task-cert-dialog-actions"><button type="button" class="btn task-cert-dialog-cancel">Schließen</button></div></div>';
});
}
function submitDialog() {
if (!currentData) { return; }
var body = collectFormData(currentData);
if (!body) { return; }
setLoading(true);
fetch(submitUrl, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
})
.then(function (res) { return res.json(); })
.then(function (result) {
if (result.success) {
dialog.close();
if (window.TaskCertAdminActions && window.TaskCertAdminActions.showToast) {
window.TaskCertAdminActions.showToast('Zuweisung als erledigt markiert.', 'success');
}
setTimeout(function () { location.reload(); }, 800);
} else {
setLoading(false);
showError(result.error || 'Unbekannter Fehler');
}
})
.catch(function (err) {
setLoading(false);
showError('Netzwerkfehler: ' + err.message);
});
}
// Event delegation
document.addEventListener('click', function (e) {
var btn = e.target.closest('.task-cert-btn-mark-completed');
if (btn) {
e.preventDefault();
var aid = parseInt(btn.getAttribute('data-assignment-id') || '0', 10);
if (aid > 0) { openDialog(aid); }
return;
}
if (e.target.closest('.task-cert-dialog-close') || e.target.closest('.task-cert-dialog-cancel')) {
dialog.close();
return;
}
});
dialog.addEventListener('submit', function (e) {
e.preventDefault();
submitDialog();
});
dialog.addEventListener('click', function (e) {
if (e.target === dialog) {
dialog.close();
}
});
})();