Dieser Commit ist enthalten in:
hendrik_gebhardt@gmx.de
2026-01-06 21:49:26 +00:00
committet von Server Deploy
Ursprung 623bbdf5dd
Commit 7d67557be4
34 geänderte Dateien mit 21416 neuen und 2367 gelöschten Zeilen

Datei anzeigen

@ -27,6 +27,8 @@
<link rel="stylesheet" href="css/gitea.css">
<link rel="stylesheet" href="css/coding.css">
<link rel="stylesheet" href="css/knowledge.css">
<link rel="stylesheet" href="css/reminders.css">
<link rel="stylesheet" href="css/contacts.css">
<link rel="stylesheet" href="css/responsive.css">
<link rel="stylesheet" href="css/mobile.css">
@ -43,7 +45,7 @@
<p>Melden Sie sich an, um fortzufahren</p>
</div>
<form id="login-form" class="login-form">
<form id="login-form" class="login-form" method="POST" action="/api/auth/login" onsubmit="return false;">
<div class="form-group">
<label for="login-username">E-Mail</label>
<input type="text" id="login-username" name="username" required autocomplete="email" autofocus placeholder="benutzer@beispiel.de">
@ -177,6 +179,7 @@
<button class="view-tab" data-view="proposals">Genehmigung</button>
<button class="view-tab" data-view="coding">Coding</button>
<button class="view-tab" data-view="knowledge">Wissen</button>
<button class="view-tab" data-view="contacts">Kontakte</button>
</nav>
</div>
@ -402,6 +405,10 @@
<!-- Dynamisch gefüllt -->
</div>
</div>
<button id="btn-new-reminder" class="btn btn-secondary btn-reminder" title="Erinnerung hinzufügen">
<svg class="icon" viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9M13.73 21a2 2 0 0 1-3.46 0" stroke="currentColor" stroke-width="2" fill="none"/></svg>
Erinnerung
</button>
<button id="btn-today" class="btn btn-secondary">Heute</button>
<div class="calendar-view-toggle">
<button class="btn btn-toggle active" data-calendar-view="month">Monat</button>
@ -504,6 +511,8 @@
</svg>
<p>Keine Kategorien</p>
</div>
<!-- Resize Handle -->
<div id="knowledge-resize-handle" class="knowledge-resize-handle"></div>
</aside>
<!-- Hauptbereich (rechts) - Einträge -->
@ -568,6 +577,47 @@
</div>
<!-- Contacts View -->
<div id="view-contacts" class="view view-contacts hidden">
<div class="contacts-header">
<h2>Kontakte</h2>
<button id="btn-new-contact" class="btn btn-primary">
<i class="fas fa-plus"></i>
Neuer Kontakt
</button>
</div>
<div class="contacts-controls">
<div class="contacts-filters">
<select id="contacts-tag-filter">
<option value="">Alle Tags</option>
</select>
<select id="contacts-sort">
<option value="created_at-desc">Neueste zuerst</option>
<option value="created_at-asc">Älteste zuerst</option>
<option value="name-asc">Name (A-Z)</option>
<option value="name-desc">Name (Z-A)</option>
<option value="company-asc">Firma (A-Z)</option>
<option value="company-desc">Firma (Z-A)</option>
</select>
</div>
</div>
<div id="contacts-grid" class="contacts-grid">
<!-- Contact cards will be rendered here -->
</div>
<div id="contacts-empty" class="contacts-empty hidden">
<i class="fas fa-address-book"></i>
<h3>Keine Kontakte vorhanden</h3>
<p>Erstellen Sie Ihren ersten Kontakt.</p>
<button class="btn btn-primary" onclick="document.getElementById('btn-new-contact').click()">
<i class="fas fa-plus"></i>
Ersten Kontakt erstellen
</button>
</div>
</div>
</main>
</div>
@ -1579,6 +1629,103 @@
</div>
</div>
<!-- Contact Modal -->
<div id="contact-modal" class="modal modal-medium hidden">
<div class="modal-header">
<h2 id="contact-modal-title">Neuer Kontakt</h2>
<button class="modal-close" data-close-modal>&times;</button>
</div>
<div class="modal-body">
<form id="contact-form">
<input type="hidden" id="contact-id" />
<div class="form-row">
<div class="form-group">
<label for="contact-first-name">Vorname</label>
<input type="text" id="contact-first-name" placeholder="Max" />
</div>
<div class="form-group">
<label for="contact-last-name">Nachname</label>
<input type="text" id="contact-last-name" placeholder="Mustermann" />
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="contact-company">Firma</label>
<input type="text" id="contact-company" placeholder="Musterfirma GmbH" />
</div>
<div class="form-group">
<label for="contact-position">Position</label>
<input type="text" id="contact-position" placeholder="Geschäftsführer" />
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="contact-email">E-Mail</label>
<input type="email" id="contact-email" placeholder="max@musterfirma.de" />
</div>
<div class="form-group">
<label for="contact-website">Website</label>
<input type="url" id="contact-website" placeholder="https://www.musterfirma.de" />
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="contact-phone">Telefon</label>
<input type="tel" id="contact-phone" placeholder="+49 30 12345678" />
</div>
<div class="form-group">
<label for="contact-mobile">Mobil</label>
<input type="tel" id="contact-mobile" placeholder="+49 170 1234567" />
</div>
</div>
<div class="form-group full-width">
<label for="contact-address">Adresse</label>
<input type="text" id="contact-address" placeholder="Musterstraße 123" />
</div>
<div class="form-row">
<div class="form-group">
<label for="contact-postal-code">PLZ</label>
<input type="text" id="contact-postal-code" placeholder="12345" />
</div>
<div class="form-group">
<label for="contact-city">Stadt</label>
<input type="text" id="contact-city" placeholder="Berlin" />
</div>
<div class="form-group">
<label for="contact-country">Land</label>
<input type="text" id="contact-country" placeholder="Deutschland" />
</div>
</div>
<div class="form-group full-width">
<label for="contact-notes">Notizen</label>
<textarea id="contact-notes" rows="3" placeholder="Zusätzliche Informationen..."></textarea>
</div>
<div class="form-group full-width">
<label for="contact-tags">Tags</label>
<input type="text" id="contact-tags" placeholder="Kunde, Partner, Lieferant" />
<div class="tags-help">Mehrere Tags mit Komma trennen</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" id="btn-delete-contact" class="btn btn-danger hidden">
<i class="fas fa-trash"></i>
Löschen
</button>
<button type="button" class="btn btn-secondary modal-cancel">Abbrechen</button>
<button type="submit" form="contact-form" class="btn btn-primary">Speichern</button>
</div>
</div>
<!-- Toast Container -->
<div id="toast-container" class="toast-container"></div>
@ -1627,6 +1774,10 @@
<svg viewBox="0 0 24 24" width="20" height="20"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" stroke="currentColor" stroke-width="2" fill="none"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" stroke="currentColor" stroke-width="2" fill="none"/></svg>
<span>Wissen</span>
</button>
<button class="mobile-nav-item" data-view="contacts">
<svg viewBox="0 0 24 24" width="20" height="20"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" stroke="currentColor" stroke-width="2" fill="none"/><circle cx="8.5" cy="7" r="4" stroke="currentColor" stroke-width="2" fill="none"/><line x1="20" y1="8" x2="20" y2="14" stroke="currentColor" stroke-width="2"/><line x1="23" y1="11" x2="17" y2="11" stroke="currentColor" stroke-width="2"/></svg>
<span>Kontakte</span>
</button>
</div>
</div>
@ -1692,11 +1843,231 @@
</div>
</div>
<!-- Reminder Modal -->
<div id="reminder-modal" class="modal hidden">
<div class="modal-content">
<div class="modal-header">
<h3 id="reminder-modal-title">Neue Erinnerung</h3>
<button class="modal-close" aria-label="Schließen">&times;</button>
</div>
<div class="modal-body">
<form id="reminder-form">
<div class="form-group">
<label for="reminder-title">Titel *</label>
<input type="text" id="reminder-title" class="form-control" required maxlength="255" placeholder="z.B. Meeting mit Kunde">
</div>
<div class="form-group">
<label for="reminder-description">Beschreibung</label>
<textarea id="reminder-description" class="form-control" rows="3" placeholder="Optionale Beschreibung..."></textarea>
</div>
<div class="form-group">
<label for="reminder-assignee">Zugewiesen an</label>
<div class="custom-select" id="reminder-assignee-wrapper">
<div class="custom-select-trigger" id="reminder-assignee-trigger">
<span class="custom-select-value">Alle Benutzer</span>
<svg class="custom-select-arrow" viewBox="0 0 24 24" width="16" height="16">
<path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="2" fill="none"/>
</svg>
</div>
<div class="custom-select-options" id="reminder-assignee-options">
<div class="custom-select-option" data-value="">
<span class="option-text">Alle Benutzer</span>
</div>
<!-- Wird dynamisch gefüllt -->
</div>
<input type="hidden" id="reminder-assignee" name="reminder-assignee" value="">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="reminder-date">Datum *</label>
<input type="date" id="reminder-date" class="form-control" required>
</div>
<div class="form-group">
<label for="reminder-time">Uhrzeit</label>
<input type="time" id="reminder-time" class="form-control" value="09:00">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="reminder-color">Farbe</label>
<div class="color-picker-wrapper">
<div class="color-picker-trigger" id="color-picker-trigger" style="background-color: #F59E0B">
<svg class="color-picker-icon" viewBox="0 0 24 24" width="16" height="16">
<path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="2" fill="none"/>
</svg>
</div>
<div class="color-picker-dropdown hidden" id="color-picker-dropdown">
<div class="color-option" data-color="#F59E0B" style="background: #F59E0B" title="Amber"></div>
<div class="color-option" data-color="#EF4444" style="background: #EF4444" title="Rot"></div>
<div class="color-option" data-color="#10B981" style="background: #10B981" title="Grün"></div>
<div class="color-option" data-color="#3B82F6" style="background: #3B82F6" title="Blau"></div>
<div class="color-option" data-color="#8B5CF6" style="background: #8B5CF6" title="Lila"></div>
<div class="color-option" data-color="#F97316" style="background: #F97316" title="Orange"></div>
<div class="color-option" data-color="#06B6D4" style="background: #06B6D4" title="Cyan"></div>
<div class="color-option" data-color="#84CC16" style="background: #84CC16" title="Lime"></div>
</div>
</div>
<input type="hidden" id="reminder-color" value="#F59E0B">
</div>
<div class="form-group">
<label for="reminder-advance">Erinnerung</label>
<div class="advance-options">
<label class="checklist-item">
<input type="checkbox" name="advance-days" value="1" checked>
<span class="checklist-checkbox"></span>
<span class="checklist-text">1 Tag vorher</span>
</label>
<label class="checklist-item">
<input type="checkbox" name="advance-days" value="2">
<span class="checklist-checkbox"></span>
<span class="checklist-text">2 Tage vorher</span>
</label>
<label class="checklist-item">
<input type="checkbox" name="advance-days" value="3">
<span class="checklist-checkbox"></span>
<span class="checklist-text">3 Tage vorher</span>
</label>
</div>
</div>
</div>
<div class="form-actions">
<div class="form-actions-left">
<button type="button" class="btn btn-secondary" id="btn-cancel-reminder">Abbrechen</button>
<button type="submit" class="btn btn-primary" id="btn-save-reminder">
<span class="btn-text">Speichern</span>
<span class="btn-loading hidden">Speichere...</span>
</button>
</div>
<button type="button" class="btn btn-danger btn-delete-reminder hidden" id="btn-delete-reminder">
<svg viewBox="0 0 24 24" width="16" height="16">
<path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2m3 0v12a2 2 0 01-2 2H7a2 2 0 01-2-2V6h14M10 11v6M14 11v6" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Löschen
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Socket.io Client -->
<script src="/socket.io/socket.io.js"></script>
<!-- Main App (ES Module) -->
<script type="module" src="js/app.js"></script>
<script type="module" src="js/reminders.js"></script>
<script type="module" src="js/contacts.js"></script>
<!-- Emergency Login Handler -->
<script>
console.log('[Login] Fallback handler wird geladen...');
function setupLoginHandler() {
const loginForm = document.getElementById('login-form');
const submitButton = loginForm?.querySelector('button[type="submit"]');
if (!loginForm) {
console.error('[Login] Login-Formular nicht gefunden!');
return;
}
console.log('[Login] Login-Formular gefunden, Handler wird eingerichtet...');
// Force override - entferne alle existierenden Handler
const newForm = loginForm.cloneNode(true);
loginForm.parentNode.replaceChild(newForm, loginForm);
newForm.addEventListener('submit', async function(e) {
e.preventDefault();
e.stopPropagation();
console.log('[Login] Submit Event ausgelöst');
const username = document.getElementById('login-username').value.trim();
const password = document.getElementById('login-password').value;
const errorEl = document.getElementById('login-error');
const newSubmitButton = newForm.querySelector('button[type="submit"]');
console.log('[Login] Username:', username);
if (!username || !password) {
errorEl.textContent = 'Bitte Benutzername und Passwort eingeben';
errorEl.classList.remove('hidden');
return;
}
// Loading state
if (newSubmitButton) {
newSubmitButton.disabled = true;
newSubmitButton.textContent = 'Anmelden...';
}
try {
console.log('[Login] Sende Login-Request...');
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password })
});
const data = await response.json();
console.log('[Login] Response Status:', response.status);
console.log('[Login] Response Data:', data);
if (response.ok && data.token) {
console.log('[Login] Login erfolgreich!');
localStorage.setItem('auth_token', data.token);
localStorage.setItem('current_user', JSON.stringify(data.user));
window.location.reload();
} else {
console.log('[Login] Login fehlgeschlagen:', data.error);
errorEl.textContent = data.error || 'Anmeldung fehlgeschlagen';
errorEl.classList.remove('hidden');
}
} catch (err) {
console.error('[Login] Netzwerkfehler:', err);
errorEl.textContent = 'Netzwerkfehler - bitte versuchen Sie es erneut';
errorEl.classList.remove('hidden');
}
// Reset button
if (newSubmitButton) {
newSubmitButton.disabled = false;
newSubmitButton.textContent = 'Anmelden';
}
});
// Additional click handler for button
const newSubmitButton = newForm.querySelector('button[type="submit"]');
if (newSubmitButton) {
newSubmitButton.addEventListener('click', function(e) {
console.log('[Login] Button clicked');
// Let form submit handle it
});
}
console.log('[Login] Handler eingerichtet');
}
// Try multiple times to ensure DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', setupLoginHandler);
} else {
setupLoginHandler();
}
// Backup after 1 second
setTimeout(setupLoginHandler, 1000);
</script>
</body>
</html>