Add Prozent im ADmin für wochenende

This commit is contained in:
2026-01-30 19:43:21 +01:00
parent 32f40124a8
commit f16593a345
9 changed files with 716 additions and 369 deletions

View File

@@ -249,6 +249,22 @@ function initDatabase() {
name TEXT
)`);
// System-Optionen-Tabelle für Wochenend-Prozentsätze
db.run(`CREATE TABLE IF NOT EXISTS system_options (
id INTEGER PRIMARY KEY DEFAULT 1,
saturday_percentage REAL DEFAULT 100,
sunday_percentage REAL DEFAULT 100,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
CHECK (id = 1)
)`);
// Standard-Eintrag für system_options erstellen falls nicht vorhanden
db.run(`INSERT OR IGNORE INTO system_options (id, saturday_percentage, sunday_percentage) VALUES (1, 100, 100)`, (err) => {
if (err && !err.message.includes('UNIQUE constraint')) {
console.warn('Warnung beim Erstellen des Standard-Eintrags für system_options:', err.message);
}
});
// Migration: Bestehende Rollen zu JSON-Arrays konvertieren
// Prüfe ob Rollen noch als einfache Strings gespeichert sind (nicht als JSON-Array)
db.all('SELECT id, role FROM users', (err, users) => {

View File

@@ -1,21 +0,0 @@
Test - Stundenerfassung
Hallo zusammen,
Mara ist auf mich mit einer Bitte herangetreten, ob ich die Stundenerfassung digitalisieren kann.
Das habe ich die letzten 2 Wochen am abend und am WE gemacht.
Ich glaube, dass das System jetzt fest fertig ist und ihr es testen könnt
Der test soll Fehler finden und mir noch die möglichkeit geben diese dann zu beheben.
Am Montag würde ich gerne eine kurze Einführung für die Leute im Büro geben.
Um ca. 11:00 Uhr für so 10-15 Minuten.
Achtet bitte am Anfangauf die Überstundenerechnung, da könnte noch der ein oder andere Fehler drin sein.
Die Seite ist im Browser zu finden unter http://stunden.sds-systemtechnik.de:3333 oder http://192.168.120.64:3333
Viele Grüße
Carsten Graf

View File

@@ -54,6 +54,43 @@ document.addEventListener('DOMContentLoaded', function() {
// LDAP-Konfiguration laden
loadLDAPConfig();
// Optionen laden
loadOptions();
// Optionen-Formular
const optionsForm = document.getElementById('optionsForm');
if (optionsForm) {
optionsForm.addEventListener('submit', async function(e) {
e.preventDefault();
const formData = {
saturday_percentage: document.getElementById('saturdayPercentage').value,
sunday_percentage: document.getElementById('sundayPercentage').value
};
try {
const response = await fetch('/admin/options', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formData)
});
const result = await response.json();
if (result.success) {
alert('Optionen wurden erfolgreich gespeichert!');
} else {
alert('Fehler: ' + (result.error || 'Optionen konnten nicht gespeichert werden'));
}
} catch (error) {
console.error('Fehler:', error);
alert('Fehler beim Speichern der Optionen');
}
});
}
// LDAP-Konfigurationsformular
const ldapConfigForm = document.getElementById('ldapConfigForm');
if (ldapConfigForm) {
@@ -161,6 +198,27 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
// Optionen laden und Formular ausfüllen
async function loadOptions() {
try {
const response = await fetch('/admin/options');
const result = await response.json();
if (result.config) {
const config = result.config;
if (document.getElementById('saturdayPercentage')) {
document.getElementById('saturdayPercentage').value = config.saturday_percentage || 0;
}
if (document.getElementById('sundayPercentage')) {
document.getElementById('sundayPercentage').value = config.sunday_percentage || 0;
}
}
} catch (error) {
console.error('Fehler beim Laden der Optionen:', error);
}
}
// LDAP-Konfiguration laden und Formular ausfüllen
async function loadLDAPConfig() {
try {

View File

@@ -4,6 +4,36 @@ let currentWeekStart = getMonday(new Date());
let currentEntries = {};
let currentHolidayDates = new Set(); // Feiertage der aktuellen Woche (YYYY-MM-DD)
let userWochenstunden = 0; // Wochenstunden des Users
let weekendPercentages = { saturday: 100, sunday: 100 }; // Wochenend-Prozentsätze (100% = normal)
// Wochenend-Prozentsätze laden
async function loadWeekendPercentages() {
try {
const response = await fetch('/api/user/weekend-percentages');
if (!response.ok) {
throw new Error('Fehler beim Laden der Wochenend-Prozentsätze');
}
const data = await response.json();
weekendPercentages.saturday = data.saturday_percentage || 100;
weekendPercentages.sunday = data.sunday_percentage || 100;
} catch (error) {
console.error('Fehler beim Laden der Wochenend-Prozentsätze:', error);
// Standardwerte verwenden
weekendPercentages.saturday = 100;
weekendPercentages.sunday = 100;
}
}
// Hilfsfunktion: Prüft ob ein Datum ein Wochenendtag ist und gibt den Prozentsatz zurück
function getWeekendPercentage(date) {
const day = date.getDay();
if (day === 6) { // Samstag
return weekendPercentages.saturday;
} else if (day === 0) { // Sonntag
return weekendPercentages.sunday;
}
return 100; // Kein Wochenende = 100% (normal)
}
// Statistiken laden
async function loadUserStats() {
@@ -110,6 +140,9 @@ document.addEventListener('DOMContentLoaded', async function() {
// Ping-IP laden
loadPingIP();
// Wochenend-Prozentsätze laden
loadWeekendPercentages();
// Statistiken laden
loadUserStats();
@@ -374,11 +407,19 @@ function renderWeek() {
// Bei ganztägigem Urlaub oder Krank sollten es bereits 8 Stunden sein (vom Backend gesetzt)
// Feiertag: 8h Basis + gearbeitete Stunden (jede gearbeitete Stunde = Überstunde)
// Bei halbem Tag Urlaub werden die Urlaubsstunden später in der Überstunden-Berechnung hinzugezählt
// Wochenend-Prozentsätze: Nur auf tatsächlich gearbeitete Stunden anwenden (nicht auf Urlaub, Krankheit, Feiertage)
let hoursToAdd = 0;
if (isHoliday) {
totalHours += 8 + (hours || 0); // 8h Feiertag + gearbeitete Stunden (= Überstunden)
hoursToAdd = 8 + (hours || 0); // 8h Feiertag + gearbeitete Stunden (= Überstunden)
} else {
totalHours += hours;
hoursToAdd = hours || 0;
// Wochenend-Prozentsatz anwenden (nur auf tatsächlich gearbeitete Stunden, nicht auf Urlaub/Krankheit)
const weekendPercentage = getWeekendPercentage(date);
if (weekendPercentage >= 100 && hours > 0 && vacationType !== 'full' && !sickStatus && !isFullDayOvertime) {
hoursToAdd = hours * (weekendPercentage / 100);
}
}
totalHours += hoursToAdd;
// Bearbeitung ist immer möglich, auch nach Abschicken
// Bei ganztägigem Urlaub oder Krank werden Zeitfelder deaktiviert; Feiertag: Anzeige, Zeitfelder optional (Überstunden)
@@ -662,10 +703,22 @@ function updateOvertimeDisplay() {
const end = new Date(`2000-01-01T${endTime}`);
const diffMs = end - start;
const hours = (diffMs / (1000 * 60 * 60)) - (breakMinutes / 60);
totalHours += hours;
// Wochenend-Prozentsatz anwenden (nur auf tatsächlich gearbeitete Stunden)
const weekendPercentage = getWeekendPercentage(date);
let adjustedHours = hours;
if (weekendPercentage >= 100 && hours > 0 && vacationType !== 'full' && !sickStatus && !isFullDayOvertime) {
adjustedHours = hours * (weekendPercentage / 100);
}
totalHours += adjustedHours;
} else if (currentEntries[dateStr]?.total_hours && !isFullDayOvertime) {
// Fallback auf gespeicherte Werte
totalHours += parseFloat(currentEntries[dateStr].total_hours) || 0;
let hours = parseFloat(currentEntries[dateStr].total_hours) || 0;
// Wochenend-Prozentsatz anwenden (nur auf tatsächlich gearbeitete Stunden)
const weekendPercentage = getWeekendPercentage(date);
if (weekendPercentage >= 100 && hours > 0 && vacationType !== 'full' && !sickStatus) {
hours = hours * (weekendPercentage / 100);
}
totalHours += hours;
}
} else if (sickStatus) {
totalHours += 8; // Krank = 8 Stunden
@@ -706,10 +759,22 @@ function updateOvertimeDisplay() {
const end = new Date(`2000-01-01T${endTime}`);
const diffMs = end - start;
const hours = (diffMs / (1000 * 60 * 60)) - (breakMinutes / 60);
totalHours += hours;
// Wochenend-Prozentsatz anwenden (nur auf tatsächlich gearbeitete Stunden)
const weekendPercentage = getWeekendPercentage(date);
let adjustedHours = hours;
if (weekendPercentage >= 100 && hours > 0 && !isFullDayOvertime) {
adjustedHours = hours * (weekendPercentage / 100);
}
totalHours += adjustedHours;
} else if (currentEntries[dateStr]?.total_hours) {
// Fallback auf gespeicherte Werte
totalHours += parseFloat(currentEntries[dateStr].total_hours) || 0;
let hours = parseFloat(currentEntries[dateStr].total_hours) || 0;
// Wochenend-Prozentsatz anwenden (nur auf tatsächlich gearbeitete Stunden)
const weekendPercentage = getWeekendPercentage(date);
if (weekendPercentage >= 100 && hours > 0 && !isFullDayOvertime) {
hours = hours * (weekendPercentage / 100);
}
totalHours += hours;
}
}
}

View File

@@ -10,9 +10,10 @@ function registerAdminRoutes(app) {
app.get('/admin', requireAdmin, (req, res) => {
db.all('SELECT id, username, firstname, lastname, role, personalnummer, wochenstunden, urlaubstage, created_at FROM users ORDER BY created_at DESC',
(err, users) => {
// LDAP-Konfiguration und Sync-Log abrufen
// LDAP-Konfiguration, Sync-Log und Optionen abrufen
db.get('SELECT * FROM ldap_config WHERE id = 1', (err, ldapConfig) => {
db.all('SELECT * FROM ldap_sync_log ORDER BY sync_started_at DESC LIMIT 10', (err, syncLogs) => {
db.get('SELECT * FROM system_options WHERE id = 1', (err, options) => {
// Parse Rollen für jeden User
const usersWithRoles = (users || []).map(u => {
let roles = [];
@@ -31,6 +32,7 @@ function registerAdminRoutes(app) {
users: usersWithRoles,
ldapConfig: ldapConfig || null,
syncLogs: syncLogs || [],
options: options || { saturday_percentage: 100, sunday_percentage: 100 },
user: {
firstname: req.session.firstname,
lastname: req.session.lastname,
@@ -42,6 +44,7 @@ function registerAdminRoutes(app) {
});
});
});
});
// Benutzer erstellen
app.post('/admin/users', requireAdmin, (req, res) => {
@@ -149,6 +152,71 @@ function registerAdminRoutes(app) {
});
}
});
// Optionen laden
app.get('/admin/options', requireAdmin, (req, res) => {
db.get('SELECT * FROM system_options WHERE id = 1', (err, options) => {
if (err) {
return res.status(500).json({ error: 'Fehler beim Laden der Optionen' });
}
// Wenn keine Optionen vorhanden, Standardwerte zurückgeben
if (!options) {
return res.json({
config: {
saturday_percentage: 100,
sunday_percentage: 100
}
});
}
res.json({ config: options });
});
});
// Optionen speichern
app.post('/admin/options', requireAdmin, (req, res) => {
const { saturday_percentage, sunday_percentage } = req.body;
// Validierung
const satPercent = parseFloat(saturday_percentage);
const sunPercent = parseFloat(sunday_percentage);
if (isNaN(satPercent) || isNaN(sunPercent)) {
return res.status(400).json({ error: 'Ungültige Prozentsätze' });
}
if (satPercent < 100 || satPercent > 200 || sunPercent < 100 || sunPercent > 200) {
return res.status(400).json({ error: 'Prozentsätze müssen zwischen 100 und 200 liegen' });
}
// Prüfe ob Eintrag existiert
db.get('SELECT id FROM system_options WHERE id = 1', (err, existing) => {
if (err) {
return res.status(500).json({ error: 'Fehler beim Prüfen der Optionen' });
}
if (existing) {
// Update
db.run('UPDATE system_options SET saturday_percentage = ?, sunday_percentage = ?, updated_at = CURRENT_TIMESTAMP WHERE id = 1',
[satPercent, sunPercent],
(err) => {
if (err) {
return res.status(500).json({ error: 'Fehler beim Speichern der Optionen' });
}
res.json({ success: true });
});
} else {
// Insert
db.run('INSERT INTO system_options (id, saturday_percentage, sunday_percentage) VALUES (1, ?, ?)',
[satPercent, sunPercent],
(err) => {
if (err) {
return res.status(500).json({ error: 'Fehler beim Speichern der Optionen' });
}
res.json({ success: true });
});
}
});
});
}
module.exports = registerAdminRoutes;

View File

@@ -27,6 +27,28 @@ function registerTimesheetRoutes(app) {
// Normalisiere sick_status: Boolean oder 1/0 zu Boolean
const isSick = sick_status === true || sick_status === 1 || sick_status === 'true' || sick_status === '1';
// Wochenend-Prozentsätze laden
db.get('SELECT saturday_percentage, sunday_percentage FROM system_options WHERE id = 1', (err, options) => {
if (err) {
console.error('Fehler beim Laden der Optionen:', err);
return res.status(500).json({ error: 'Fehler beim Laden der Optionen' });
}
const saturdayPercentage = options?.saturday_percentage || 100;
const sundayPercentage = options?.sunday_percentage || 100;
// Hilfsfunktion: Prüft ob ein Datum ein Wochenendtag ist und gibt den Prozentsatz zurück
function getWeekendPercentage(dateStr) {
const date = new Date(dateStr);
const day = date.getDay();
if (day === 6) { // Samstag
return saturdayPercentage;
} else if (day === 0) { // Sonntag
return sundayPercentage;
}
return 100; // Kein Wochenende = 100% (normal)
}
// User-Daten laden (für Überstunden-Berechnung)
db.get('SELECT wochenstunden FROM users WHERE id = ?', [userId], (err, user) => {
if (err) {
@@ -73,6 +95,11 @@ function registerTimesheetRoutes(app) {
const end = new Date(`2000-01-01T${normalizedEndTime}`);
const diffMs = end - start;
total_hours = (diffMs / (1000 * 60 * 60)) - (break_minutes / 60);
// Wochenend-Prozentsatz anwenden (nur auf tatsächlich gearbeitete Stunden, nicht auf Urlaub/Krankheit)
const weekendPercentage = getWeekendPercentage(date);
if (weekendPercentage >= 100 && total_hours > 0 && !isSick && vacation_type !== 'full') {
total_hours = total_hours * (weekendPercentage / 100);
}
// Bei halbem Tag Urlaub: total_hours bleibt die tatsächlich gearbeiteten Stunden
// Die 4 Stunden Urlaub werden nur in der Überstunden-Berechnung hinzugezählt
}
@@ -147,6 +174,7 @@ function registerTimesheetRoutes(app) {
});
});
});
});
// API: Feiertage für einen Zeitraum (Dashboard-Anzeige)
app.get('/api/timesheet/holidays', requireAuth, (req, res) => {

View File

@@ -39,6 +39,20 @@ function registerUserRoutes(app) {
});
});
// API: Wochenend-Prozentsätze abrufen
app.get('/api/user/weekend-percentages', requireAuth, (req, res) => {
db.get('SELECT saturday_percentage, sunday_percentage FROM system_options WHERE id = 1', (err, options) => {
if (err) {
return res.status(500).json({ error: 'Fehler beim Abrufen der Wochenend-Prozentsätze' });
}
// Wenn keine Optionen vorhanden, Standardwerte zurückgeben
res.json({
saturday_percentage: options?.saturday_percentage || 100,
sunday_percentage: options?.sunday_percentage || 100
});
});
});
// API: User-Daten abrufen (Wochenstunden)
app.get('/api/user/data', requireAuth, (req, res) => {
const userId = req.session.userId;
@@ -187,6 +201,27 @@ function registerUserRoutes(app) {
app.get('/api/user/stats', requireAuth, (req, res) => {
const userId = req.session.userId;
// Wochenend-Prozentsätze laden
db.get('SELECT saturday_percentage, sunday_percentage FROM system_options WHERE id = 1', (err, options) => {
if (err) {
return res.status(500).json({ error: 'Fehler beim Laden der Optionen' });
}
const saturdayPercentage = options?.saturday_percentage || 100;
const sundayPercentage = options?.sunday_percentage || 100;
// Hilfsfunktion: Prüft ob ein Datum ein Wochenendtag ist und gibt den Prozentsatz zurück
function getWeekendPercentage(dateStr) {
const date = new Date(dateStr);
const day = date.getDay();
if (day === 6) { // Samstag
return saturdayPercentage;
} else if (day === 0) { // Sonntag
return sundayPercentage;
}
return 100; // Kein Wochenende = 100% (normal)
}
// User-Daten abrufen
db.get('SELECT wochenstunden, urlaubstage, overtime_offset_hours FROM users WHERE id = ?', [userId], (err, user) => {
if (err || !user) {
@@ -397,12 +432,24 @@ function registerUserRoutes(app) {
weekVacationHours += 4; // Halber Tag = 4 Stunden
// Bei halbem Tag Urlaub können noch Arbeitsstunden vorhanden sein
if (entry.total_hours && !isFullDayOvertime) {
weekTotalHours += entry.total_hours;
let hours = entry.total_hours;
// Wochenend-Prozentsatz anwenden (nur auf tatsächlich gearbeitete Stunden)
const weekendPercentage = getWeekendPercentage(entry.date);
if (weekendPercentage >= 100 && hours > 0 && !entry.sick_status) {
hours = hours * (weekendPercentage / 100);
}
weekTotalHours += hours;
}
} else {
// Kein Urlaub - zähle nur Arbeitsstunden (wenn nicht 8 Überstunden)
if (entry.total_hours && !isFullDayOvertime) {
weekTotalHours += entry.total_hours;
let hours = entry.total_hours;
// Wochenend-Prozentsatz anwenden (nur auf tatsächlich gearbeitete Stunden, nicht auf Krankheit)
const weekendPercentage = getWeekendPercentage(entry.date);
if (weekendPercentage > 0 && hours > 0 && !entry.sick_status) {
hours = hours * (1 + weekendPercentage / 100);
}
weekTotalHours += hours;
}
}
});
@@ -456,13 +503,14 @@ function registerUserRoutes(app) {
overtimeOffsetHours: overtimeOffsetHours
});
}
});
});
});
});
});
});
});
}); // getHolidaysForDateRange.then
}); // db.all (allEntries)
}); // weeks.forEach
}); // db.all (weeks)
}); // db.all (allVacationEntries)
}); // db.get (user)
}); // db.get (options)
}); // app.get
}
module.exports = registerUserRoutes;

View File

@@ -142,6 +142,27 @@ function registerVerwaltungRoutes(app) {
const userId = req.params.id;
const { week_start, week_end } = req.query;
// Wochenend-Prozentsätze laden
db.get('SELECT saturday_percentage, sunday_percentage FROM system_options WHERE id = 1', (err, options) => {
if (err) {
return res.status(500).json({ error: 'Fehler beim Laden der Optionen' });
}
const saturdayPercentage = options?.saturday_percentage || 100;
const sundayPercentage = options?.sunday_percentage || 100;
// Hilfsfunktion: Prüft ob ein Datum ein Wochenendtag ist und gibt den Prozentsatz zurück
function getWeekendPercentage(dateStr) {
const date = new Date(dateStr);
const day = date.getDay();
if (day === 6) { // Samstag
return saturdayPercentage;
} else if (day === 0) { // Sonntag
return sundayPercentage;
}
return 100; // Kein Wochenende = 100% (normal)
}
// User-Daten abrufen
db.get('SELECT wochenstunden, urlaubstage, overtime_offset_hours FROM users WHERE id = ?', [userId], (err, user) => {
if (err || !user) {
@@ -190,12 +211,24 @@ function registerVerwaltungRoutes(app) {
vacationHours += 4; // Halber Tag = 4 Stunden
// Bei halbem Tag Urlaub können noch Arbeitsstunden vorhanden sein
if (entry.total_hours) {
totalHours += entry.total_hours;
let hours = entry.total_hours;
// Wochenend-Prozentsatz anwenden (nur auf tatsächlich gearbeitete Stunden)
const weekendPercentage = getWeekendPercentage(entry.date);
if (weekendPercentage >= 100 && hours > 0 && !entry.sick_status) {
hours = hours * (weekendPercentage / 100);
}
totalHours += hours;
}
} else {
// Kein Urlaub - zähle nur Arbeitsstunden
if (entry.total_hours) {
totalHours += entry.total_hours;
let hours = entry.total_hours;
// Wochenend-Prozentsatz anwenden (nur auf tatsächlich gearbeitete Stunden, nicht auf Krankheit)
const weekendPercentage = getWeekendPercentage(entry.date);
if (weekendPercentage > 0 && hours > 0 && !entry.sick_status) {
hours = hours * (1 + weekendPercentage / 100);
}
totalHours += hours;
}
}
});
@@ -249,6 +282,7 @@ function registerVerwaltungRoutes(app) {
});
});
});
});
// API: Admin-Kommentar speichern
app.put('/api/verwaltung/timesheet/:id/comment', requireVerwaltung, (req, res) => {

View File

@@ -203,6 +203,43 @@
</div>
</div>
<div class="options-section" style="margin-top: 40px;">
<div class="collapsible-header" onclick="toggleOptionsSection()" style="cursor: pointer; padding: 15px; background-color: #f5f5f5; border: 1px solid #ddd; border-radius: 4px; display: flex; justify-content: space-between; align-items: center;">
<h2 style="margin: 0;">Optionen</h2>
<span id="optionsToggleIcon" style="font-size: 18px; transition: transform 0.3s;">▼</span>
</div>
<div id="optionsContent" style="display: none; padding: 20px; border: 1px solid #ddd; border-top: none; border-radius: 0 0 4px 4px; background-color: #fff;">
<div class="options-form">
<h3>Wochenend-Prozentsätze</h3>
<p style="margin-bottom: 20px; color: #666;">Konfigurieren Sie die Prozentsätze für die Wochenendstunden. 100% entspricht normal, 150% entspricht 1,5 mal, 200% entspricht doppelt.</p>
<form id="optionsForm">
<div class="form-row">
<div class="form-group">
<label for="saturdayPercentage">Samstag-Prozentsatz</label>
<select id="saturdayPercentage" name="saturday_percentage" class="form-control" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
<% for (let i = 100; i <= 200; i += 5) { %>
<option value="<%= i %>" <%= (typeof options !== 'undefined' && options && options.saturday_percentage == i) ? 'selected' : '' %>><%= i %>%</option>
<% } %>
</select>
</div>
<div class="form-group">
<label for="sundayPercentage">Sonntag-Prozentsatz</label>
<select id="sundayPercentage" name="sunday_percentage" class="form-control" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
<% for (let i = 100; i <= 200; i += 5) { %>
<option value="<%= i %>" <%= (typeof options !== 'undefined' && options && options.sunday_percentage == i) ? 'selected' : '' %>><%= i %>%</option>
<% } %>
</select>
</div>
</div>
<button type="submit" class="btn btn-primary">Optionen speichern</button>
</form>
</div>
</div>
</div>
<div class="ldap-sync-section" style="margin-top: 40px;">
<div class="collapsible-header" onclick="toggleLDAPSection()" style="cursor: pointer; padding: 15px; background-color: #f5f5f5; border: 1px solid #ddd; border-radius: 4px; display: flex; justify-content: space-between; align-items: center;">
<h2 style="margin: 0;">LDAP-Synchronisation</h2>
@@ -375,6 +412,20 @@
}
}
// Optionen-Sektion ein-/ausklappen
function toggleOptionsSection() {
const content = document.getElementById('optionsContent');
const icon = document.getElementById('optionsToggleIcon');
if (content.style.display === 'none') {
content.style.display = 'block';
icon.style.transform = 'rotate(180deg)';
} else {
content.style.display = 'none';
icon.style.transform = 'rotate(0deg)';
}
}
// Rollenwechsel-Handler
document.addEventListener('DOMContentLoaded', function() {
const roleSwitcher = document.getElementById('roleSwitcher');