📚 Improved codebase structure & logging enhancements 🚀

This commit is contained in:
2025-06-01 04:26:09 +02:00
parent 1a3bfa4094
commit 19eeed46fb
29 changed files with 1918 additions and 494 deletions

View File

@ -1079,7 +1079,7 @@
inset 0 1px 0 rgba(255, 255, 255, 0.2),
0 0 0 1px rgba(255, 255, 255, 0.05);
}
.notification.show {
@apply translate-x-0 opacity-100;
}
@ -1100,7 +1100,7 @@
inset 0 1px 0 rgba(255, 255, 255, 0.3),
0 0 0 1px rgba(255, 255, 255, 0.1);
}
.notification-success {
@apply text-green-100;
background: linear-gradient(135deg,
@ -1114,7 +1114,7 @@
inset 0 1px 0 rgba(255, 255, 255, 0.4),
0 0 0 1px rgba(34, 197, 94, 0.3);
}
.notification-error {
@apply text-red-100;
background: linear-gradient(135deg,
@ -1128,7 +1128,7 @@
inset 0 1px 0 rgba(255, 255, 255, 0.4),
0 0 0 1px rgba(239, 68, 68, 0.3);
}
.notification-warning {
@apply text-yellow-100;
background: linear-gradient(135deg,
@ -1142,7 +1142,7 @@
inset 0 1px 0 rgba(255, 255, 255, 0.4),
0 0 0 1px rgba(245, 158, 11, 0.3);
}
.notification-info {
@apply text-blue-100;
background: linear-gradient(135deg,
@ -1209,7 +1209,7 @@
inset 0 1px 0 rgba(255, 255, 255, 0.15),
0 0 0 1px rgba(255, 255, 255, 0.05);
}
.alert-success {
@apply text-green-900 dark:text-green-100;
background: linear-gradient(135deg,
@ -1218,7 +1218,7 @@
rgba(34, 197, 94, 0.08) 100%);
border: 1px solid rgba(34, 197, 94, 0.3);
}
.alert-error {
@apply text-red-900 dark:text-red-100;
background: linear-gradient(135deg,
@ -1227,7 +1227,7 @@
rgba(239, 68, 68, 0.08) 100%);
border: 1px solid rgba(239, 68, 68, 0.3);
}
.alert-warning {
@apply text-yellow-900 dark:text-yellow-100;
background: linear-gradient(135deg,
@ -1236,7 +1236,7 @@
rgba(245, 158, 11, 0.08) 100%);
border: 1px solid rgba(245, 158, 11, 0.3);
}
.alert-info {
@apply text-blue-900 dark:text-blue-100;
background: linear-gradient(135deg,

File diff suppressed because one or more lines are too long

View File

@ -422,20 +422,298 @@ class AdminDashboard {
}
// User-Management
showUserModal() {
console.log('👤 Benutzer-Modal wird angezeigt');
this.showNotification('Benutzer-Funktionen werden geladen...', 'info');
showUserModal(userId = null) {
const isEdit = userId !== null;
const title = isEdit ? 'Benutzer bearbeiten' : 'Neuer Benutzer';
// Modal HTML erstellen
const modalHtml = `
<div id="user-modal" class="fixed inset-0 bg-black/60 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div class="bg-white dark:bg-slate-800 rounded-2xl p-8 max-w-md w-full shadow-2xl transform scale-100 transition-all duration-300">
<div class="flex justify-between items-center mb-6">
<h3 class="text-2xl font-bold text-slate-900 dark:text-white">${title}</h3>
<button onclick="this.closest('#user-modal').remove()" class="p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors">
<svg class="w-6 h-6 text-slate-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
<form id="user-form" class="space-y-4">
<div>
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">E-Mail-Adresse *</label>
<input type="email" name="email" id="user-email" required
class="w-full px-4 py-3 border border-slate-300 dark:border-slate-600 rounded-xl
focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all
dark:bg-slate-700 dark:text-white bg-slate-50">
</div>
<div>
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Benutzername</label>
<input type="text" name="username" id="user-username"
class="w-full px-4 py-3 border border-slate-300 dark:border-slate-600 rounded-xl
focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all
dark:bg-slate-700 dark:text-white bg-slate-50">
</div>
<div>
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Name</label>
<input type="text" name="name" id="user-name"
class="w-full px-4 py-3 border border-slate-300 dark:border-slate-600 rounded-xl
focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all
dark:bg-slate-700 dark:text-white bg-slate-50">
</div>
<div>
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Passwort ${isEdit ? '(leer lassen für keine Änderung)' : '*'}</label>
<input type="password" name="password" id="user-password" ${!isEdit ? 'required' : ''}
class="w-full px-4 py-3 border border-slate-300 dark:border-slate-600 rounded-xl
focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all
dark:bg-slate-700 dark:text-white bg-slate-50">
</div>
<div>
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Rolle</label>
<select name="role" id="user-role"
class="w-full px-4 py-3 border border-slate-300 dark:border-slate-600 rounded-xl
focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all
dark:bg-slate-700 dark:text-white bg-slate-50">
<option value="user">Benutzer</option>
<option value="admin">Administrator</option>
</select>
</div>
${isEdit ? `
<div class="flex items-center space-x-2">
<input type="checkbox" name="is_active" id="user-active"
class="w-4 h-4 text-blue-600 bg-slate-100 border-slate-300 rounded focus:ring-blue-500">
<label for="user-active" class="text-sm font-medium text-slate-700 dark:text-slate-300">Aktiv</label>
</div>
` : ''}
<div class="flex justify-end space-x-3 mt-8 pt-6 border-t border-slate-200 dark:border-slate-600">
<button type="button" onclick="this.closest('#user-modal').remove()"
class="px-6 py-3 bg-slate-200 dark:bg-slate-600 text-slate-700 dark:text-slate-300
rounded-xl hover:bg-slate-300 dark:hover:bg-slate-500 transition-colors font-medium">
Abbrechen
</button>
<button type="submit" id="user-submit-btn"
class="px-6 py-3 bg-gradient-to-r from-blue-500 to-blue-600 text-white
rounded-xl hover:from-blue-600 hover:to-blue-700 transition-all duration-300
shadow-lg hover:shadow-xl font-medium">
${isEdit ? 'Aktualisieren' : 'Erstellen'}
</button>
</div>
</form>
</div>
</div>
`;
// Modal zum DOM hinzufügen
document.body.insertAdjacentHTML('beforeend', modalHtml);
// Event-Listener für das Formular
const form = document.getElementById('user-form');
form.addEventListener('submit', (e) => {
e.preventDefault();
e.stopPropagation();
if (isEdit) {
this.updateUser(userId, new FormData(form));
} else {
this.createUser(new FormData(form));
}
});
// Bei Bearbeitung: Benutzer-Daten laden
if (isEdit) {
this.loadUserData(userId);
}
// Fokus auf erstes Eingabefeld
setTimeout(() => {
document.getElementById('user-email').focus();
}, 100);
}
async loadUserData(userId) {
try {
const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
if (data.success) {
const user = data.user;
// Formular mit Benutzerdaten füllen
document.getElementById('user-email').value = user.email || '';
document.getElementById('user-username').value = user.username || '';
document.getElementById('user-name').value = user.name || '';
document.getElementById('user-role').value = user.is_admin ? 'admin' : 'user';
const activeCheckbox = document.getElementById('user-active');
if (activeCheckbox) {
activeCheckbox.checked = user.is_active !== false;
}
} else {
this.showNotification('❌ Fehler beim Laden der Benutzerdaten', 'error');
}
} catch (error) {
console.error('Fehler beim Laden der Benutzerdaten:', error);
this.showNotification('❌ Fehler beim Laden der Benutzerdaten', 'error');
}
}
async createUser(formData) {
const submitBtn = document.getElementById('user-submit-btn');
const originalText = submitBtn.innerHTML;
try {
// Loading-Zustand
submitBtn.innerHTML = '<div class="animate-spin rounded-full h-5 w-5 border-b-2 border-white mx-auto"></div>';
submitBtn.disabled = true;
// FormData zu JSON konvertieren
const userData = {
email: formData.get('email'),
username: formData.get('username') || formData.get('email').split('@')[0],
name: formData.get('name'),
password: formData.get('password'),
is_admin: formData.get('role') === 'admin'
};
const response = await fetch(`${this.apiBaseUrl}/api/admin/users`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
},
body: JSON.stringify(userData)
});
const data = await response.json();
if (data.success) {
this.showNotification('✅ Benutzer erfolgreich erstellt!', 'success');
document.getElementById('user-modal').remove();
// Seite nach 1 Sekunde neu laden um neue Benutzerliste zu zeigen
setTimeout(() => {
window.location.reload();
}, 1000);
} else {
this.showNotification(`❌ Fehler: ${data.error}`, 'error');
}
} catch (error) {
console.error('Fehler beim Erstellen des Benutzers:', error);
this.showNotification('❌ Fehler beim Erstellen des Benutzers', 'error');
} finally {
// Button zurücksetzen
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
}
}
async updateUser(userId, formData) {
const submitBtn = document.getElementById('user-submit-btn');
const originalText = submitBtn.innerHTML;
try {
// Loading-Zustand
submitBtn.innerHTML = '<div class="animate-spin rounded-full h-5 w-5 border-b-2 border-white mx-auto"></div>';
submitBtn.disabled = true;
// FormData zu JSON konvertieren
const userData = {
email: formData.get('email'),
username: formData.get('username'),
name: formData.get('name'),
is_admin: formData.get('role') === 'admin',
is_active: formData.get('is_active') === 'on'
};
// Passwort nur hinzufügen wenn es gesetzt wurde
const password = formData.get('password');
if (password && password.trim()) {
userData.password = password;
}
const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
},
body: JSON.stringify(userData)
});
const data = await response.json();
if (data.success) {
this.showNotification('✅ Benutzer erfolgreich aktualisiert!', 'success');
document.getElementById('user-modal').remove();
// Seite nach 1 Sekunde neu laden um aktualisierte Benutzerliste zu zeigen
setTimeout(() => {
window.location.reload();
}, 1000);
} else {
this.showNotification(`❌ Fehler: ${data.error}`, 'error');
}
} catch (error) {
console.error('Fehler beim Aktualisieren des Benutzers:', error);
this.showNotification('❌ Fehler beim Aktualisieren des Benutzers', 'error');
} finally {
// Button zurücksetzen
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
}
}
editUser(userId) {
console.log(`✏️ Benutzer ${userId} wird bearbeitet`);
this.showNotification(`Benutzer ${userId} wird bearbeitet...`, 'info');
this.showUserModal(userId);
}
async deleteUser(userId, userName) {
if (!confirm(`🗑️ Möchten Sie den Benutzer "${userName}" wirklich löschen?`)) return;
if (!confirm(`🗑️ Möchten Sie den Benutzer "${userName}" wirklich löschen?\n\nDiese Aktion kann nicht rückgängig gemacht werden!`)) {
return;
}
this.showNotification(`🔄 Benutzer "${userName}" wird gelöscht...`, 'info');
try {
this.showNotification(`🔄 Benutzer "${userName}" wird gelöscht...`, 'info');
const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.csrfToken
}
});
const data = await response.json();
if (data.success) {
this.showNotification(`✅ Benutzer "${userName}" erfolgreich gelöscht!`, 'success');
// Seite nach 1 Sekunde neu laden um aktualisierte Benutzerliste zu zeigen
setTimeout(() => {
window.location.reload();
}, 1000);
} else {
this.showNotification(`❌ Fehler beim Löschen: ${data.error}`, 'error');
}
} catch (error) {
console.error('Fehler beim Löschen des Benutzers:', error);
this.showNotification('❌ Fehler beim Löschen des Benutzers', 'error');
}
}
// Printer-Management

File diff suppressed because it is too large Load Diff