webinterface/client/js/main.js

381 lines
16 KiB
JavaScript

import { showAlert, showConfirm, sanitizeInput } from './shared_functions.js';
import * as api from './api_service.js';
import { initializeChat, createNewChat, handleSendMessage } from './chat_manager.js'; // Only import needed functions directly used by main
import * as ui from './chat_ui.js'; // Need UI functions
// --- DOM Elements ---
// Moved some element selections inside setup functions to ensure they exist
const bodyElement = document.body;
console.log("main: ")
console.log(bodyElement)
let themeToggleButton = null; // Initialize as null
let logoutBtn = null; // Initialize as null
// --- Initialization ---
document.addEventListener('DOMContentLoaded', () => {
console.log("DOM Content Loaded. Body ID:", bodyElement.id); // Log body ID
// Common elements present on all/most pages
themeToggleButton = document.getElementById('themeToggleBtn');
logoutBtn = document.getElementById('logoutBtn');
loadThemePreference(); // Load theme early
// Add common listeners if elements exist
if (themeToggleButton) {
console.log("Attaching theme listener");
themeToggleButton.addEventListener('click', toggleTheme);
} else {
console.warn("Theme toggle button not found");
}
if (logoutBtn) {
console.log("Attaching logout listener");
logoutBtn.addEventListener('click', logout);
} else {
console.warn("Logout button not found");
}
// Page specific initialization with error handling for the setup promises
if (bodyElement.id === 'chat-page') {
console.log("Running Chat Page Setup");
setupChatPage()
.catch(error => {
console.error("Error during Chat Page Setup:", error);
showAlert("Ein kritischer Fehler ist beim Laden der Chat-Seite aufgetreten.", "error");
});
} else if (bodyElement.id === 'admin-page') {
console.log("Running Admin Page Setup");
setupAdminPage()
.catch(error => {
// This catch is now primarily for unexpected errors *within* setupAdminPage's try block
// as checkAdminStatus errors should be handled more specifically inside.
console.error("Unhandled error during Admin Page Setup:", error);
if (!error.message?.includes("handled")) { // Avoid double alerts if handled internally
showAlert("Ein unerwarteter Fehler ist beim Laden der Admin-Seite aufgetreten.", "error");
}
});
} else if (bodyElement.id === 'login-page') {
console.log("Login/Register page setup handled by auth.js");
} else {
console.warn("No specific page setup for body ID:", bodyElement.id);
}
});
// --- Page Setup Functions ---
async function setupChatPage() {
console.log("setupChatPage started");
if (!localStorage.getItem('token')) {
redirectToLogin('Kein Token gefunden. Bitte einloggen.');
return;
}
// Select elements specific to chat page *inside* setup
const adminPermissionsBtn = document.getElementById('adminPermissionsBtn');
const newChatButton = document.getElementById('newChatButton');
const chatInput = document.getElementById('chatInput');
const sendButton = document.getElementById('sendButton');
// Load user data first
await loadUserDataForChat(); // This function now handles UI updates internally
// Setup chat specific event listeners *after* confirming elements exist
if (newChatButton) {
console.log("Attaching new chat listener");
newChatButton.addEventListener('click', createNewChat);
} else {
console.error("New Chat button not found!");
}
if (sendButton) {
console.log("Attaching send listener");
sendButton.addEventListener('click', processUserInput);
} else {
console.error("Send button not found!");
}
if (chatInput) {
console.log("Attaching input listeners");
chatInput.addEventListener('keydown', handleChatInputKeydown);
chatInput.addEventListener('input', ui.autoResizeTextarea);
// Initial resize
ui.autoResizeTextarea();
} else {
console.error("Chat input not found!");
}
if (adminPermissionsBtn) {
console.log("Attaching admin button listener");
adminPermissionsBtn.addEventListener('click', () => { window.location.href = 'admin.html'; });
} else {
// This might be expected if the user is not admin, handled by loadUserDataForChat
// console.warn("Admin permissions button not found (may be expected)");
}
// Initialize chat manager AFTER setting up listeners that might use its functions
try {
console.log("Initializing Chat Manager...");
await initializeChat();
console.log("Chat Manager Initialized.");
} catch(error) {
console.error("Error initializing chat manager:", error);
showAlert("Fehler beim Initialisieren des Chats.", "error");
}
}
async function setupAdminPage() {
console.log("setupAdminPage started");
if (!localStorage.getItem('token')) {
redirectToLogin('Kein Token gefunden. Bitte einloggen.');
return;
}
// Select elements specific to admin page
const loadUserListBtn = document.getElementById('loadUserListBtn');
const welcomeButton = document.getElementById('welcomeButton');
const userListDiv = document.getElementById('user-list'); // Also select user list container
if (!userListDiv) {
console.error("User list container ('user-list') not found on admin page!");
// Optionally show an error message in the main area if the container is missing
}
try {
// Check admin status first. If this fails, it will throw an error.
// checkAdminStatus handles redirection/alerts for 401/403.
await checkAdminStatus();
console.log("Admin status confirmed. Proceeding with admin setup.");
// ---- If admin check passes, THEN setup listeners and load list ----
// Setup 'Reload List' button listener
if (loadUserListBtn) {
console.log("Attaching load user list listener");
loadUserListBtn.addEventListener('click', () => {
console.log("Reload list button clicked.");
loadUserList(); // Call loadUserList on click
});
} else {
console.error("Load user list button ('loadUserListBtn') not found!");
}
// Setup 'Back to Chat' button listener
if (welcomeButton) {
console.log("Attaching welcome button listener");
welcomeButton.addEventListener('click', () => {
console.log("Welcome button clicked, redirecting...");
window.location.href = 'welcome.html';
});
} else {
console.error("Welcome (back to chat) button ('welcomeButton') not found!");
}
// Load list initially ONLY if admin check succeeded
console.log("Initiating initial user list load.");
await loadUserList(); // Load the list data
console.log("Initial user list load attempt finished.");
} catch (error) {
// This catch block now primarily handles errors from checkAdminStatus
// or potentially the initial loadUserList call if it throws unexpectedly.
console.error("SetupAdminPage failed during admin check or initial load:", error);
// Most user-facing errors (like redirection or alerts for auth/network issues)
// should have been handled within checkAdminStatus or loadUserList's call to handleApiError.
// We might not need to show another alert here unless it's a truly unexpected setup problem.
// Mark the error as handled to avoid potential double alerts from the outer catch block.
error.message += " (handled in setupAdminPage)";
}
}
// --- Event Handlers ---
function handleChatInputKeydown(event) {
// console.log("Keydown:", event.key); // Debugging keystrokes
if (event.key === 'Enter' && !event.shiftKey) {
console.log("Enter pressed"); // Debugging Enter key
event.preventDefault();
processUserInput();
}
}
function processUserInput() {
const chatInput = document.getElementById('chatInput'); // Re-select or ensure it's available
if (!chatInput) {
console.error("Cannot process user input: chatInput not found.");
return;
}
const messageText = sanitizeInput(chatInput.value.trim());
console.log("Processing user input:", messageText); // Debugging input processing
if (messageText) {
handleSendMessage(messageText) // Call chat manager function
.then(() => {
console.log("Message handled by manager.");
ui.clearChatInput();
})
.catch(error => {
console.error("Error sending message via manager:", error);
// UI should already be enabled by chat_manager's finally block
});
} else {
console.log("Input is empty, not sending.");
}
}
// --- User Data and Auth ---
async function loadUserDataForChat() {
const usernameSpan = document.getElementById('username');
const isAdminSpan = document.getElementById('isAdmin');
const adminPermissionsBtn = document.getElementById('adminPermissionsBtn');
try {
console.log("Loading user data for chat page...");
const data = await api.getUserData();
console.log("User data received:", data);
if (usernameSpan) usernameSpan.textContent = data.user || 'Unbekannt';
if (isAdminSpan) isAdminSpan.textContent = data.isAdmin ? 'Ja' : 'Nein';
if (adminPermissionsBtn) {
// Control display based on fetched data
adminPermissionsBtn.style.display = data.isAdmin ? 'inline-block' : 'none';
console.log("Admin button display set to:", adminPermissionsBtn.style.display);
}
} catch (error) {
console.error("Failed to load user data:", error);
// Display error state in UI
if (usernameSpan) usernameSpan.textContent = 'Fehler';
if (isAdminSpan) isAdminSpan.textContent = 'Fehler';
handleApiError(error, 'Benutzerdaten laden'); // Show alert, potentially redirect
}
}
// --- Definition of checkAdminStatus --- Moved here to ensure it's defined before use
async function checkAdminStatus() {
console.log("Checking admin status...");
try {
// Assuming api.getAdminData() makes the /api/auth/admin call
// and throws an error (e.g., 401, 403) if the user is not an admin.
await api.getAdminData();
console.log("Admin access confirmed.");
// No need to return true, successful execution implies admin status
} catch (error) {
console.warn("Admin status check failed:", error.status, error.message);
if (error.status === 403 || error.status === 401) { // Forbidden or Unauthorized
showAlert('Zugriff verweigert. Nur Admins erlaubt.', 'error');
window.location.href = 'welcome.html'; // Redirect non-admins immediately
} else {
// Handle other errors (e.g., network error)
handleApiError(error, 'Admin-Status prüfen');
}
// IMPORTANT: Re-throw the error AFTER handling redirection/alert
// This signals to the caller (setupAdminPage) that the check failed.
throw error;
}
}
async function loadUserList() {
const userListDiv = document.getElementById('user-list'); // Select inside function
if (!userListDiv) {
console.error("User list container not found!");
return;
}
userListDiv.innerHTML = '<p style="padding: 15px; color: var(--text-secondary);">Lade Benutzer...</p>'; // Loading state
try {
const users = await api.getAllUsers();
userListDiv.innerHTML = ''; // Clear loading/previous list
if (users && users.length > 0) {
users.forEach(user => {
const userDiv = document.createElement('div');
userDiv.classList.add('user-list-item');
userDiv.dataset.userId = user._id;
const usernameP = document.createElement('p');
usernameP.innerHTML = `<strong>User:</strong> ${sanitizeInput(user.username)}`;
const emailP = document.createElement('p');
emailP.innerHTML = `<strong>Email:</strong> ${sanitizeInput(user.email)}`;
const adminP = document.createElement('p');
adminP.innerHTML = `<strong>Admin:</strong> ${user.isAdmin ? 'Ja' : 'Nein'}`;
const deleteButton = document.createElement('button');
deleteButton.classList.add('button-delete', 'header-btn');
deleteButton.style.backgroundColor = 'var(--error-color)';
deleteButton.textContent = 'Löschen';
deleteButton.addEventListener('click', () => handleDeleteUser(user._id, user.isAdmin, user.username)); // Pass userListDiv here if needed
userDiv.append(usernameP, emailP, adminP, deleteButton);
userListDiv.appendChild(userDiv);
});
} else {
userListDiv.innerHTML = '<p style="padding: 15px; color: var(--text-secondary);">Keine Benutzer gefunden.</p>';
}
} catch (error) {
handleApiError(error, 'Benutzerliste laden');
userListDiv.innerHTML = '<p style="padding: 15px; color: var(--error-color);">Fehler beim Laden der Benutzerliste.</p>';
}
}
async function handleDeleteUser(userId, isAdmin, username) {
const userListDiv = document.getElementById('user-list'); // Select inside function if needed
const message = `Möchten Sie den Benutzer "${sanitizeInput(username)}" wirklich löschen? ${isAdmin ? ' Dies ist ein Admin!' : ''}`;
const confirmed = await showConfirm(message, 'error');
if (confirmed) {
try {
await api.deleteUserById(userId);
showAlert(`Benutzer "${sanitizeInput(username)}" erfolgreich gelöscht.`, 'success');
// Remove user from list visually immediately
const userDiv = userListDiv?.querySelector(`.user-list-item[data-user-id="${userId}"]`);
if (userDiv) userDiv.remove();
// Or reload the whole list: await loadUserList();
} catch (error) {
handleApiError(error, 'Benutzer löschen');
}
}
}
// --- Theme Toggling ---
function toggleTheme() {
const isDarkMode = bodyElement.classList.toggle('dark-theme');
if (themeToggleButton) {
themeToggleButton.textContent = isDarkMode ? '🌙' : '☀️';
}
localStorage.setItem('theme', isDarkMode ? 'dark' : 'light');
}
function loadThemePreference() {
const savedTheme = localStorage.getItem('theme');
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
const isDark = savedTheme === 'dark' || (!savedTheme && prefersDark);
bodyElement.classList.toggle('dark-theme', isDark); // Set class based on isDark boolean
if (themeToggleButton) { // Check if button exists before setting text
themeToggleButton.textContent = isDark ? '🌙' : '☀️';
}
}
// --- Generic Error Handling ---
function handleApiError(error, context) {
console.error(`API Error during ${context}:`, error);
if (error.status === 401 || error.status === 403) {
redirectToLogin(`Sitzung abgelaufen oder nicht autorisiert (${context}). Bitte erneut einloggen.`);
} else if (error.message.includes('Network Error')) {
showAlert(`Netzwerkfehler bei "${context}". Server nicht erreichbar.`, 'error');
} else {
// Show specific message from API if available, otherwise generic
showAlert(`Fehler bei "${context}": ${error.data?.message || error.message || 'Unbekannter Fehler'}`, 'error');
}
}
// --- Utility Functions --- (logout, redirectToLogin same as before)
function logout() {
localStorage.removeItem('token');
window.location.href = 'index.html';
}
function redirectToLogin(message) {
if (message) showAlert(message, 'error');
setTimeout(() => { window.location.href = 'index.html'; }, 1500);
}