FirstCommit
This commit is contained in:
167
views/dashboard.ejs
Normal file
167
views/dashboard.ejs
Normal file
@@ -0,0 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de-DE">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Content-Language" content="de-DE">
|
||||
<title>Dashboard - Stundenerfassung</title>
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="navbar">
|
||||
<div class="container">
|
||||
<h1>Stundenerfassung</h1>
|
||||
<div class="nav-right">
|
||||
<span>Willkommen, <%= user.firstname %> <%= user.lastname %></span>
|
||||
<% if (user.roles && user.roles.length > 1) { %>
|
||||
<select id="roleSwitcher" class="role-switcher" style="margin-right: 10px; padding: 5px 10px; border-radius: 4px; border: 1px solid #ddd;">
|
||||
<% const roleLabels = { 'mitarbeiter': 'Mitarbeiter', 'verwaltung': 'Verwaltung', 'admin': 'Administrator' }; %>
|
||||
<% user.roles.forEach(function(role) { %>
|
||||
<option value="<%= role %>" <%= user.currentRole === role ? 'selected' : '' %>><%= roleLabels[role] || role %></option>
|
||||
<% }); %>
|
||||
</select>
|
||||
<% } %>
|
||||
<a href="/logout" class="btn btn-secondary">Abmelden</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container dashboard-container">
|
||||
<div class="dashboard-layout">
|
||||
<div class="dashboard">
|
||||
<div class="week-selector">
|
||||
<button id="prevWeek" class="btn btn-secondary">◀ Vorherige Woche</button>
|
||||
<h2 id="weekTitle">Kalenderwoche</h2>
|
||||
<button id="nextWeek" class="btn btn-secondary">Nächste Woche ▶</button>
|
||||
</div>
|
||||
|
||||
<div id="timesheetTable">
|
||||
<!-- Wird mit JavaScript gefüllt -->
|
||||
</div>
|
||||
|
||||
<div class="summary">
|
||||
<div class="summary-item">
|
||||
<strong>Gesamtstunden diese Woche:</strong>
|
||||
<span id="totalHours">0.00 h</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button id="submitWeek" class="btn btn-success" onclick="window.submitWeekHandler(event)">Woche abschicken</button>
|
||||
<p class="help-text">Stunden werden automatisch gespeichert. Am Ende der Woche können Sie die Stunden abschicken.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Auswertung: Überstunden und Urlaubstage -->
|
||||
<div class="user-stats-panel" id="userStatsPanel">
|
||||
<h3>Ihre Auswertung</h3>
|
||||
<div class="stat-card stat-overtime">
|
||||
<div class="stat-label">Aktuelle Überstunden</div>
|
||||
<div class="stat-value" id="currentOvertime">-</div>
|
||||
<div class="stat-unit">Stunden</div>
|
||||
</div>
|
||||
<div class="stat-card stat-vacation">
|
||||
<div class="stat-label">Verbleibende Urlaubstage</div>
|
||||
<div class="stat-value" id="remainingVacation">-</div>
|
||||
<div class="stat-unit">von <span id="totalVacation">-</span> Tagen</div>
|
||||
</div>
|
||||
|
||||
<!-- API-URLs für Zeiterfassung -->
|
||||
<div class="stat-card stat-api-urls" style="margin-top: 20px; padding: 15px; box-sizing: border-box; width: 100%;">
|
||||
<h4 style="margin-bottom: 15px; font-size: 14px; color: #555;">Schnelle Zeiterfassung</h4>
|
||||
<div style="margin-bottom: 12px;">
|
||||
<label style="display: block; font-size: 12px; color: #666; margin-bottom: 5px;">Kommen (Check-in):</label>
|
||||
<div style="display: flex; gap: 8px; align-items: center; width: 100%;">
|
||||
<input type="text" id="checkinUrl" readonly value=""
|
||||
style="flex: 1; min-width: 0; padding: 6px 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 12px; background-color: #f9f9f9;">
|
||||
<button onclick="copyToClipboard('checkinUrl')" class="btn btn-secondary btn-sm" style="padding: 6px 12px; font-size: 12px; flex-shrink: 0;">Kopieren</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label style="display: block; font-size: 12px; color: #666; margin-bottom: 5px;">Gehen (Check-out):</label>
|
||||
<div style="display: flex; gap: 8px; align-items: center; width: 100%;">
|
||||
<input type="text" id="checkoutUrl" readonly value=""
|
||||
style="flex: 1; min-width: 0; padding: 6px 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 12px; background-color: #f9f9f9;">
|
||||
<button onclick="copyToClipboard('checkoutUrl')" class="btn btn-secondary btn-sm" style="padding: 6px 12px; font-size: 12px; flex-shrink: 0;">Kopieren</button>
|
||||
</div>
|
||||
</div>
|
||||
<p style="margin-top: 10px; font-size: 11px; color: #888; line-height: 1.4;">
|
||||
Diese URLs können Sie in einer App eintragen oder direkt im Browser aufrufen, um Ihre Arbeitszeiten zu erfassen.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/dashboard.js"></script>
|
||||
<script>
|
||||
// URL-Kopier-Funktion
|
||||
function copyToClipboard(inputId) {
|
||||
const input = document.getElementById(inputId);
|
||||
input.select();
|
||||
input.setSelectionRange(0, 99999); // Für mobile Geräte
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
const button = event.target;
|
||||
const originalText = button.textContent;
|
||||
button.textContent = 'Kopiert!';
|
||||
button.style.backgroundColor = '#27ae60';
|
||||
setTimeout(() => {
|
||||
button.textContent = originalText;
|
||||
button.style.backgroundColor = '';
|
||||
}, 2000);
|
||||
} catch (err) {
|
||||
alert('Fehler beim Kopieren. Bitte manuell kopieren.');
|
||||
}
|
||||
}
|
||||
|
||||
// URLs mit aktueller Domain aktualisieren
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const userId = '<%= user.id %>';
|
||||
const baseUrl = window.location.origin;
|
||||
const checkinInput = document.getElementById('checkinUrl');
|
||||
const checkoutInput = document.getElementById('checkoutUrl');
|
||||
if (checkinInput) checkinInput.value = `${baseUrl}/api/checkin/${userId}`;
|
||||
if (checkoutInput) checkoutInput.value = `${baseUrl}/api/checkout/${userId}`;
|
||||
|
||||
// Rollenwechsel-Handler
|
||||
const roleSwitcher = document.getElementById('roleSwitcher');
|
||||
if (roleSwitcher) {
|
||||
roleSwitcher.addEventListener('change', async function() {
|
||||
const newRole = this.value;
|
||||
try {
|
||||
const response = await fetch('/api/user/switch-role', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ role: newRole })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
// Redirect basierend auf neuer Rolle
|
||||
if (newRole === 'admin') {
|
||||
window.location.href = '/admin';
|
||||
} else if (newRole === 'verwaltung') {
|
||||
window.location.href = '/verwaltung';
|
||||
} else {
|
||||
window.location.href = '/dashboard';
|
||||
}
|
||||
} else {
|
||||
alert('Fehler beim Wechseln der Rolle: ' + (result.error || 'Unbekannter Fehler'));
|
||||
// Wert zurücksetzen
|
||||
this.value = '<%= user.currentRole || "mitarbeiter" %>';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Rollenwechsel:', error);
|
||||
alert('Fehler beim Wechseln der Rolle');
|
||||
// Wert zurücksetzen
|
||||
this.value = '<%= user.currentRole || "mitarbeiter" %>';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user