|
|
|
@ -4,49 +4,12 @@ const mins = document.getElementById('minuten');
|
|
|
|
const NewEntryButton = document.getElementById('newEntrySubmitButton')
|
|
|
|
const NewEntryButton = document.getElementById('newEntrySubmitButton')
|
|
|
|
const SETStudySaveButton = document.getElementById('SETStudySaveButton')
|
|
|
|
const SETStudySaveButton = document.getElementById('SETStudySaveButton')
|
|
|
|
const SETMonthGoalSaveButton = document.getElementById('SETMonthGoalSaveButton')
|
|
|
|
const SETMonthGoalSaveButton = document.getElementById('SETMonthGoalSaveButton')
|
|
|
|
const SETLdcNameSaveButton = document.getElementById('SETLdcNameSaveButton')
|
|
|
|
|
|
|
|
const rule55hCheck = document.getElementById('rule55hCheck')
|
|
|
|
|
|
|
|
const openViewOfEntry = document.getElementById('openViewOfEntry')
|
|
|
|
|
|
|
|
const openViewOfEntryIcon = document.getElementById('openViewOfEntryIcon')
|
|
|
|
|
|
|
|
const ActivitysTable = document.getElementById('ActivitysTable')
|
|
|
|
|
|
|
|
const timerCard = document.getElementById('timerCard')
|
|
|
|
|
|
|
|
const toggleSortOptions = document.getElementById('toggleSortOptions')
|
|
|
|
|
|
|
|
const sortOptionsRow = document.getElementById('sortOptionsRow')
|
|
|
|
|
|
|
|
const sortFieldButton = document.getElementById('sortFieldButton')
|
|
|
|
|
|
|
|
const sortFieldLabel = document.getElementById('sortFieldLabel')
|
|
|
|
|
|
|
|
const sortFieldMenu = document.getElementById('sortFieldMenu')
|
|
|
|
|
|
|
|
const sortFieldOptions = document.querySelectorAll('.sortFieldOption')
|
|
|
|
|
|
|
|
const sortDirectionToggle = document.getElementById('sortDirectionToggle')
|
|
|
|
|
|
|
|
const sortDirectionIcon = document.getElementById('sortDirectionIcon')
|
|
|
|
|
|
|
|
const shareIcon = document.getElementById('share_icon')
|
|
|
|
|
|
|
|
const shareReportModalEl = document.getElementById('shareReportModal')
|
|
|
|
|
|
|
|
const shareReportStatus = document.getElementById('shareReportStatus')
|
|
|
|
|
|
|
|
const shareReportPreview = document.getElementById('shareReportPreview')
|
|
|
|
|
|
|
|
var allowToSend = false;
|
|
|
|
var allowToSend = false;
|
|
|
|
const monate = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"];
|
|
|
|
const monate = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"];
|
|
|
|
|
|
|
|
const aktuellerMonat = monate[new Date().getMonth()];
|
|
|
|
|
|
|
|
// Aktuelles Datum
|
|
|
|
const currentDate = new Date();
|
|
|
|
const currentDate = new Date();
|
|
|
|
|
|
|
|
|
|
|
|
// 55h-Regel (Jahresansicht): wird beim Start aus den Settings geladen und beim Umschalten
|
|
|
|
|
|
|
|
// live aktualisiert, damit getActualDataAndFillView() sie synchron verwenden kann.
|
|
|
|
|
|
|
|
var rule55Active = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Individuell vergebbarer Name für "LDC" (SettingsID 4), überall im UI verwendet statt fest "LDC".
|
|
|
|
|
|
|
|
var ldcLabel = 'LDC';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Sortierung der Aktivitäten-Tabelle: wird aus dem Cache (localStorage) geladen/gespeichert.
|
|
|
|
|
|
|
|
var sortField = 'date';
|
|
|
|
|
|
|
|
var sortDirection = 'asc';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Ob die Filter/Sortier-Optionen gerade sichtbar sind (wird ebenfalls im Cache gespeichert).
|
|
|
|
|
|
|
|
// Standardmäßig ausgeblendet, bis der Nutzer sie einmal selbst einblendet.
|
|
|
|
|
|
|
|
var isFilterVisible = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Ob die Aktivitäten-Tabelle gerade maximiert ist (Timer-Karte ist dann ausgeblendet).
|
|
|
|
|
|
|
|
var isTableMaximized = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Einträge des gerade angezeigten Monats, für den WhatsApp-Bericht (share_icon) wiederverwendet.
|
|
|
|
|
|
|
|
var currentMonthEntries = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Trigger
|
|
|
|
// Trigger
|
|
|
|
@ -54,189 +17,19 @@ var currentMonthEntries = [];
|
|
|
|
|
|
|
|
|
|
|
|
// Wenn das Dokument komplett geladen ist
|
|
|
|
// Wenn das Dokument komplett geladen ist
|
|
|
|
document.addEventListener('DOMContentLoaded', (event) => {
|
|
|
|
document.addEventListener('DOMContentLoaded', (event) => {
|
|
|
|
initDB().then(async () => {
|
|
|
|
initDB().then(() => {
|
|
|
|
console.log('IndexedDB erfolgreich initialisiert.');
|
|
|
|
console.log('IndexedDB erfolgreich initialisiert.');
|
|
|
|
// Hier kannst du die App weiter initialisieren, z.B. Daten laden oder die UI aufbauen
|
|
|
|
// Hier kannst du die App weiter initialisieren, z.B. Daten laden oder die UI aufbauen
|
|
|
|
|
|
|
|
|
|
|
|
// 55h-Regel Einstellung laden, bevor die erste Jahresansicht berechnet wird
|
|
|
|
|
|
|
|
await loadRule55Setting();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// LDC-Bezeichnung laden, bevor die Tabelle erstmalig gefüllt wird
|
|
|
|
|
|
|
|
await loadLdcLabel();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Gespeicherte Sortierung der Aktivitäten-Tabelle aus dem Cache laden
|
|
|
|
|
|
|
|
loadSortPreference();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Gespeicherte Sichtbarkeit der Filter/Sortier-Optionen aus dem Cache laden
|
|
|
|
|
|
|
|
loadFilterVisibility();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Bildschirm mit dem Inhalt für den aktuellen Tag füllen
|
|
|
|
// Bildschirm mit dem Inhalt für den aktuellen Tag füllen
|
|
|
|
getActualDataAndFillView();
|
|
|
|
getActualDataAndFillView();
|
|
|
|
|
|
|
|
|
|
|
|
//loadInitialData();
|
|
|
|
//loadInitialData();
|
|
|
|
}).catch((error) => {
|
|
|
|
}).catch((error) => {
|
|
|
|
console.error('Fehler bei der Initialisierung der IndexedDB:', error);
|
|
|
|
console.error('Fehler bei der Initialisierung der IndexedDB:', error);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Behebt die Bootstrap-Konsolenwarnung "Blocked aria-hidden on an element because its
|
|
|
|
|
|
|
|
// descendant retained focus": beim Schließen eines Modals (z.B. per "X"-Button) setzt
|
|
|
|
|
|
|
|
// Bootstrap aria-hidden="true", obwohl der geklickte Button noch fokussiert ist. Fix: Fokus
|
|
|
|
|
|
|
|
// vor dem Ausblenden gezielt vom Modal wegnehmen. Gilt für alle Modals der Seite.
|
|
|
|
|
|
|
|
document.querySelectorAll('.modal').forEach(modalEl => {
|
|
|
|
|
|
|
|
modalEl.addEventListener('hide.bs.modal', () => {
|
|
|
|
|
|
|
|
if (document.activeElement && modalEl.contains(document.activeElement)) {
|
|
|
|
|
|
|
|
document.activeElement.blur()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Lädt die 55h-Regel Einstellung (SettingsID 3) aus der DB, setzt rule55Active
|
|
|
|
|
|
|
|
// und synchronisiert die Checkbox sowie den Badge in der Jahres-Card.
|
|
|
|
|
|
|
|
async function loadRule55Setting() {
|
|
|
|
|
|
|
|
const result = await getAllEntries('settings')
|
|
|
|
|
|
|
|
const setting = result.find(element => element.SettingsID === 3)
|
|
|
|
|
|
|
|
rule55Active = (setting == undefined) ? false : !!parseInt(setting.SettingsValue)
|
|
|
|
|
|
|
|
rule55hCheck.checked = rule55Active
|
|
|
|
|
|
|
|
updateRule55Badge()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Zeigt/versteckt den "55h-Regel aktiv"-Hinweis an der Jahres-Card
|
|
|
|
|
|
|
|
function updateRule55Badge() {
|
|
|
|
|
|
|
|
document.getElementById('rule55Badge').classList.toggle('d-none', !rule55Active)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Einstellungen wenn die 55h-Regel umgeschaltet wird
|
|
|
|
|
|
|
|
rule55hCheck.addEventListener('change', () => {
|
|
|
|
|
|
|
|
rule55Active = rule55hCheck.checked
|
|
|
|
|
|
|
|
updateRule55Badge()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Rule55SettingsData = {
|
|
|
|
|
|
|
|
SettingsID: 3,
|
|
|
|
|
|
|
|
SettingsValue: rule55Active ? 1 : 0,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getAllEntries('settings')
|
|
|
|
|
|
|
|
.then(function(result) {
|
|
|
|
|
|
|
|
const SETDBData = result.find(element => element.SettingsID === 3)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (SETDBData != undefined) {
|
|
|
|
|
|
|
|
updateEntry(SETDBData.id, 'settings', Rule55SettingsData)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
addEntry(Rule55SettingsData, 'settings')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Jahresansicht mit/ohne Deckel neu berechnen
|
|
|
|
|
|
|
|
getActualDataAndFillView(cursorMonth, cursorYear)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// TABELLE MAXIMIEREN
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Aktivitäten-Tabelle vergrößern/verkleinern: Timer-Karte klappt beim Maximieren
|
|
|
|
|
|
|
|
// animiert weg, um Platz zu schaffen; die Tabelle wächst gleichzeitig.
|
|
|
|
|
|
|
|
openViewOfEntry.addEventListener('click', () => {
|
|
|
|
|
|
|
|
isTableMaximized = !isTableMaximized
|
|
|
|
|
|
|
|
ActivitysTable.classList.toggle('ActivitysTableMaximized', isTableMaximized)
|
|
|
|
|
|
|
|
timerCard.classList.toggle('timerCollapsed', isTableMaximized)
|
|
|
|
|
|
|
|
openViewOfEntryIcon.src = isTableMaximized
|
|
|
|
|
|
|
|
? openViewOfEntryIcon.src.replace('open.png', 'close.png')
|
|
|
|
|
|
|
|
: openViewOfEntryIcon.src.replace('close.png', 'open.png')
|
|
|
|
|
|
|
|
openViewOfEntry.title = isTableMaximized ? 'Tabelle minimieren' : 'Tabelle maximieren'
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// SORTIERUNG DER AKTIVITÄTEN-TABELLE
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Lädt die gespeicherte Sortierung aus dem Cache (localStorage) und synchronisiert die Steuerelemente
|
|
|
|
|
|
|
|
function loadSortPreference() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
const saved = JSON.parse(localStorage.getItem('piomintTableSort'))
|
|
|
|
|
|
|
|
if (saved && saved.field) {
|
|
|
|
|
|
|
|
sortField = saved.field
|
|
|
|
|
|
|
|
sortDirection = (saved.direction === 'desc') ? 'desc' : 'asc'
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
console.error('Sortierung konnte nicht aus dem Cache geladen werden:', error)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const selectedOption = Array.from(sortFieldOptions).find(option => option.dataset.value === sortField)
|
|
|
|
|
|
|
|
sortFieldLabel.innerText = selectedOption ? selectedOption.dataset.label : 'Datum'
|
|
|
|
|
|
|
|
sortDirectionIcon.innerText = (sortDirection === 'asc') ? 'A → Z' : 'Z → A'
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Speichert die aktuelle Sortierung im Cache (localStorage)
|
|
|
|
|
|
|
|
function saveSortPreference() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
localStorage.setItem('piomintTableSort', JSON.stringify({ field: sortField, direction: sortDirection }))
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
console.error('Sortierung konnte nicht im Cache gespeichert werden:', error)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Eigener Dropdown für die Sortier-Eigenschaft (statt <select>) öffnen/schließen
|
|
|
|
|
|
|
|
sortFieldButton.addEventListener('click', (event) => {
|
|
|
|
|
|
|
|
event.stopPropagation()
|
|
|
|
|
|
|
|
sortFieldMenu.classList.toggle('d-none')
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Außerhalb des Menüs klicken schließt es wieder
|
|
|
|
|
|
|
|
document.addEventListener('click', (event) => {
|
|
|
|
|
|
|
|
if (!sortFieldMenu.classList.contains('d-none') && !sortFieldMenu.contains(event.target) && event.target !== sortFieldButton) {
|
|
|
|
|
|
|
|
sortFieldMenu.classList.add('d-none')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sortFieldOptions.forEach(option => {
|
|
|
|
|
|
|
|
option.addEventListener('click', () => {
|
|
|
|
|
|
|
|
sortField = option.dataset.value
|
|
|
|
|
|
|
|
sortFieldLabel.innerText = option.dataset.label
|
|
|
|
|
|
|
|
sortFieldMenu.classList.add('d-none')
|
|
|
|
|
|
|
|
saveSortPreference()
|
|
|
|
|
|
|
|
getActualDataAndFillView(cursorMonth, cursorYear)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sortDirectionToggle.addEventListener('click', () => {
|
|
|
|
|
|
|
|
sortDirection = (sortDirection === 'asc') ? 'desc' : 'asc'
|
|
|
|
|
|
|
|
sortDirectionIcon.innerText = (sortDirection === 'asc') ? 'A → Z' : 'Z → A'
|
|
|
|
|
|
|
|
saveSortPreference()
|
|
|
|
|
|
|
|
getActualDataAndFillView(cursorMonth, cursorYear)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// FILTER/SORTIER-OPTIONEN EIN-/AUSBLENDEN
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Lädt die gespeicherte Sichtbarkeit der Filter-Optionen aus dem Cache (localStorage)
|
|
|
|
|
|
|
|
function loadFilterVisibility() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
const saved = localStorage.getItem('piomintFilterVisible')
|
|
|
|
|
|
|
|
if (saved !== null) {
|
|
|
|
|
|
|
|
isFilterVisible = (saved === 'true')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
console.error('Filter-Sichtbarkeit konnte nicht aus dem Cache geladen werden:', error)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sortOptionsRow.classList.toggle('sortOptionsCollapsed', !isFilterVisible)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toggleSortOptions.addEventListener('click', () => {
|
|
|
|
|
|
|
|
isFilterVisible = !isFilterVisible
|
|
|
|
|
|
|
|
sortOptionsRow.classList.toggle('sortOptionsCollapsed', !isFilterVisible)
|
|
|
|
|
|
|
|
// Offenes Dropdown-Menü beim Einklappen der Filterzeile mit schließen
|
|
|
|
|
|
|
|
if (!isFilterVisible) {
|
|
|
|
|
|
|
|
sortFieldMenu.classList.add('d-none')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
localStorage.setItem('piomintFilterVisible', isFilterVisible)
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
console.error('Filter-Sichtbarkeit konnte nicht im Cache gespeichert werden:', error)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Änderungen überwachen damit die das Formular nicht zu früh abgesendet wird
|
|
|
|
// Änderungen überwachen damit die das Formular nicht zu früh abgesendet wird
|
|
|
|
@ -248,13 +41,7 @@ mins.addEventListener('input', () => {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
document.getElementById('sonstigesInput').addEventListener('input', () => {
|
|
|
|
document.getElementById('sonstigesInput').addEventListener('input', () => {
|
|
|
|
checkInput();
|
|
|
|
checkInput();
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Button-Status beim Öffnen des Modals einmal anhand der Standardwerte (z.B. Minuten = 0) setzen,
|
|
|
|
|
|
|
|
// da sonst ohne ein tatsächliches 'input'-Event der Button trotz gültiger Vorbelegung deaktiviert bleibt
|
|
|
|
|
|
|
|
document.getElementById('newEntryModal').addEventListener('show.bs.modal', () => {
|
|
|
|
|
|
|
|
checkInput();
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Einstellungen wenn Neuer Eintrag erstellt wird
|
|
|
|
// Einstellungen wenn Neuer Eintrag erstellt wird
|
|
|
|
NewEntryButton.addEventListener('click', () => {
|
|
|
|
NewEntryButton.addEventListener('click', () => {
|
|
|
|
@ -273,8 +60,8 @@ NewEntryButton.addEventListener('click', () => {
|
|
|
|
sonstigesText.style.display = 'none';
|
|
|
|
sonstigesText.style.display = 'none';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Berechnen der Duration (Stunden sind optional -> ohne Eingabe wird 0 gespeichert)
|
|
|
|
// Berechnen der Duration
|
|
|
|
const duration = ((parseInt(hours.value) || 0)*60) + parseInt(mins.value)
|
|
|
|
const duration = (parseInt(hours.value)*60) + parseInt(mins.value)
|
|
|
|
|
|
|
|
|
|
|
|
const newEntryData = {
|
|
|
|
const newEntryData = {
|
|
|
|
date: document.getElementById('datum').value,
|
|
|
|
date: document.getElementById('datum').value,
|
|
|
|
@ -369,135 +156,12 @@ SETMonthGoalSaveButton.addEventListener('click', () => {
|
|
|
|
SETMonthGoalSaveButton.classList.add('d-none')
|
|
|
|
SETMonthGoalSaveButton.classList.add('d-none')
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Lädt die individuelle LDC-Bezeichnung (SettingsID 4) aus der DB, setzt ldcLabel,
|
|
|
|
|
|
|
|
// füllt das Einstellungen-Feld vor und wendet den Namen überall im UI an.
|
|
|
|
|
|
|
|
async function loadLdcLabel() {
|
|
|
|
|
|
|
|
const result = await getAllEntries('settings')
|
|
|
|
|
|
|
|
const setting = result.find(element => element.SettingsID === 4)
|
|
|
|
|
|
|
|
ldcLabel = (setting == undefined || !setting.SettingsValue) ? 'LDC' : setting.SettingsValue
|
|
|
|
|
|
|
|
document.getElementById('ldcNameInput').value = ldcLabel
|
|
|
|
|
|
|
|
applyLdcLabel()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Setzt die aktuelle LDC-Bezeichnung überall dort, wo sie im UI (außerhalb der Tabelle) auftaucht.
|
|
|
|
|
|
|
|
// Die Tabelle selbst bekommt den Namen bei jedem Render über fillTableWithEntries(...).
|
|
|
|
|
|
|
|
function applyLdcLabel() {
|
|
|
|
|
|
|
|
document.getElementById('ldcCheckLabel').innerText = ldcLabel
|
|
|
|
|
|
|
|
document.getElementById('editldcCheckLabel').innerText = ldcLabel
|
|
|
|
|
|
|
|
document.getElementById('monthHourLDCLabel').innerText = ldcLabel
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SETLdcNameSaveButton.addEventListener('click', () => {
|
|
|
|
|
|
|
|
getAllEntries('settings')
|
|
|
|
|
|
|
|
.then(function(result) {
|
|
|
|
|
|
|
|
const SETDBData = result.find(element => element.SettingsID === 4)
|
|
|
|
|
|
|
|
actualSettingsEntryID = SETDBData ? SETDBData.id : undefined;
|
|
|
|
|
|
|
|
actualSettings = SETDBData ? SETDBData.SettingsValue : undefined;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// AKTUELLE DATEN AUS FELD ÜBERNHEMEN - bei leerem Feld auf "LDC" zurückfallen
|
|
|
|
|
|
|
|
var ActInput = document.getElementById('ldcNameInput').value.trim() || 'LDC'
|
|
|
|
|
|
|
|
document.getElementById('ldcNameInput').value = ActInput
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const LdcNameSettingsData = {
|
|
|
|
|
|
|
|
SettingsID: 4,
|
|
|
|
|
|
|
|
SettingsValue: ActInput,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ÜBERPRÜFEN OB EIN EINTRAG MTI DER SETTINGS ID VORHANDEN IST - WENN JA DANN UPDATE WENN NEIN DANN NEUEN ERSTELLEN
|
|
|
|
|
|
|
|
if ( actualSettings != undefined ) {
|
|
|
|
|
|
|
|
updateEntry(actualSettingsEntryID, 'settings', LdcNameSettingsData)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
addEntry(LdcNameSettingsData, 'settings')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ldcLabel = ActInput
|
|
|
|
|
|
|
|
applyLdcLabel()
|
|
|
|
|
|
|
|
// Tabelle neu füllen, damit die Typ-Spalte den neuen Namen sofort übernimmt
|
|
|
|
|
|
|
|
getActualDataAndFillView(cursorMonth, cursorYear)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SETLdcNameSaveButton.classList.add('d-none')
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// BERICHT FÜR WHATSAPP TEILEN
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Baut den vorformatierten Bericht für den gerade angezeigten Monat (WhatsApp-Formatierung: *fett*)
|
|
|
|
|
|
|
|
function buildMonthReportText() {
|
|
|
|
|
|
|
|
const monthLabel = `${monate[cursorMonth]} ${cursorYear}`
|
|
|
|
|
|
|
|
const dienstHours = document.getElementById('monthHourService').innerText
|
|
|
|
|
|
|
|
const bibelstudien = document.getElementById('studysinput').value
|
|
|
|
|
|
|
|
const ldcHours = document.getElementById('monthHourLDC').innerText
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Sonstige Einträge nach ihrem individuellen Bemerkungstext gruppieren und Stunden je Gruppe summieren
|
|
|
|
|
|
|
|
const sonstigeGroups = {}
|
|
|
|
|
|
|
|
currentMonthEntries
|
|
|
|
|
|
|
|
.filter(entry => entry.type === 3)
|
|
|
|
|
|
|
|
.forEach(entry => {
|
|
|
|
|
|
|
|
const label = entry.sondertext || 'Sonstiges'
|
|
|
|
|
|
|
|
sonstigeGroups[label] = (sonstigeGroups[label] || 0) + entry.duration
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var message = `Bericht: *${monthLabel}*\n`
|
|
|
|
async function getActualDataAndFillView(monat = currentDate.getMonth() + 1, jahr = currentDate.getFullYear()) {
|
|
|
|
message += `Dienst: ${dienstHours}h\n`
|
|
|
|
|
|
|
|
message += `Bibelstudien: ${bibelstudien}\n`
|
|
|
|
|
|
|
|
message += `Bemerkungen:\n`
|
|
|
|
|
|
|
|
message += `• ${ldcLabel}: ${ldcHours}h`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object.keys(sonstigeGroups).forEach(label => {
|
|
|
|
|
|
|
|
message += `\n• ${label}: ${formatDuration(sonstigeGroups[label], true)}h`
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return message
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Kopiert Text in die Zwischenablage - mit Fallback für Umgebungen ohne Clipboard-API
|
|
|
|
|
|
|
|
async function copyTextToClipboard(text) {
|
|
|
|
|
|
|
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
|
|
|
|
|
|
await navigator.clipboard.writeText(text)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const textarea = document.createElement('textarea')
|
|
|
|
|
|
|
|
textarea.value = text
|
|
|
|
|
|
|
|
textarea.style.position = 'fixed'
|
|
|
|
|
|
|
|
textarea.style.opacity = '0'
|
|
|
|
|
|
|
|
document.body.appendChild(textarea)
|
|
|
|
|
|
|
|
textarea.select()
|
|
|
|
|
|
|
|
document.execCommand('copy')
|
|
|
|
|
|
|
|
document.body.removeChild(textarea)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Bestätigung als Vorschau-Modal statt kurzem Icon-Blitz: so sieht man den Bericht direkt
|
|
|
|
|
|
|
|
// (auch praktisch, wenn man ihn gar nicht kopieren, sondern nur ansehen möchte) und kann
|
|
|
|
|
|
|
|
// in Ruhe wieder schließen.
|
|
|
|
|
|
|
|
shareIcon.addEventListener('click', () => {
|
|
|
|
|
|
|
|
const message = buildMonthReportText()
|
|
|
|
|
|
|
|
shareReportPreview.innerText = message
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
copyTextToClipboard(message)
|
|
|
|
|
|
|
|
.then(() => {
|
|
|
|
|
|
|
|
shareReportStatus.innerText = '✓ In die Zwischenablage kopiert'
|
|
|
|
|
|
|
|
shareReportStatus.style.color = 'rgb(120,170,86)'
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
|
|
|
console.error('Bericht konnte nicht in die Zwischenablage kopiert werden:', error)
|
|
|
|
|
|
|
|
shareReportStatus.innerText = 'Kopieren nicht möglich - Text unten manuell markieren'
|
|
|
|
|
|
|
|
shareReportStatus.style.color = '#dc3545'
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
|
|
new bootstrap.Modal(shareReportModalEl).show()
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function getActualDataAndFillView(monat = currentDate.getMonth(), jahr = currentDate.getFullYear()) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
|
|
|
|
|
|
|
|
// Einfüfen des aktuellen Monats
|
|
|
|
// Einfüfen des aktuellen Monats
|
|
|
|
document.getElementById('actualMonthName').innerHTML = monate[monat !== 12 ? monat : 0];
|
|
|
|
document.getElementById('actualMonthName').innerHTML = monate[monat - 1];
|
|
|
|
console.log("AKTUELLER MONAT SYSTEM: ", monat)
|
|
|
|
|
|
|
|
console.log("AKTUELLER MONAT REAL: ", currentDate.getMonth())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Settings vor ausfüllen
|
|
|
|
// Settings vor ausfüllen
|
|
|
|
|
|
|
|
|
|
|
|
@ -513,14 +177,10 @@ async function getActualDataAndFillView(monat = currentDate.getMonth(), jahr = c
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Filter funktion aufrufen und entsprechend mit dem aktuellen Datum füllen
|
|
|
|
// Filter funktion aufrufen und entsprechend mit dem aktuellen Datum füllen
|
|
|
|
const filteredEntries = await filterEntriesByMonthYear(monat === 12 ? 1 : monat + 1, jahr);
|
|
|
|
const filteredEntries = await filterEntriesByMonthYear(monat, jahr);
|
|
|
|
currentMonthEntries = filteredEntries
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log("update-complete")
|
|
|
|
|
|
|
|
console.log(jahr)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Tabelle mit den aktuellen informationen füllen (funktion triggern und Daten übergeben)
|
|
|
|
// Tabelle mit den aktuellen informationen füllen (funktion triggern und Daten übergeben)
|
|
|
|
fillTableWithEntries(filteredEntries, sortField, sortDirection, ldcLabel)
|
|
|
|
fillTableWithEntries(filteredEntries)
|
|
|
|
|
|
|
|
|
|
|
|
// Ausgabe der Daten in den Log für DEV möglich
|
|
|
|
// Ausgabe der Daten in den Log für DEV möglich
|
|
|
|
// console.log('Gefilterte Einträge für September 2024:', filteredEntries);
|
|
|
|
// console.log('Gefilterte Einträge für September 2024:', filteredEntries);
|
|
|
|
@ -546,16 +206,16 @@ async function getActualDataAndFillView(monat = currentDate.getMonth(), jahr = c
|
|
|
|
document.getElementById('monthHourLDC').innerText = formatDuration(sumDurations(filteredEntries,2,true), true)
|
|
|
|
document.getElementById('monthHourLDC').innerText = formatDuration(sumDurations(filteredEntries,2,true), true)
|
|
|
|
document.getElementById('monthHourOther').innerText = formatDuration(sumDurations(filteredEntries,3,true), true)
|
|
|
|
document.getElementById('monthHourOther').innerText = formatDuration(sumDurations(filteredEntries,3,true), true)
|
|
|
|
|
|
|
|
|
|
|
|
// Jahres Ansicht füllen (Dienstjahr, gekoppelt an den gerade angezeigten Monat/Jahr)
|
|
|
|
// Jahres Ansicht füllen
|
|
|
|
// Bei aktiver 55h-Regel wird jeder Monat mit LDC/Sonstiges-Anteil auf max. 55h gedeckelt,
|
|
|
|
var requestYear = currentDate.getFullYear()
|
|
|
|
// reine Dienststunden zählen dabei immer voll (siehe calculateServiceYearTotal).
|
|
|
|
if (currentDate.getMonth() +1 >= 9) {
|
|
|
|
var requestServiceYear = getServiceYear(new Date(jahr, monat, 1));
|
|
|
|
requestYear += 1;
|
|
|
|
var yearEntries = await filterEntriesByServiceYear(requestServiceYear)
|
|
|
|
}
|
|
|
|
var yearData = formatDuration(calculateServiceYearTotal(yearEntries, rule55Active), true)
|
|
|
|
var yearData = await filterEntriesByMonthYear(null, requestYear)
|
|
|
|
|
|
|
|
yearData = formatDuration(sumDurations(yearData, null, true), true)
|
|
|
|
document.getElementById('yearHours').innerText = yearData
|
|
|
|
document.getElementById('yearHours').innerText = yearData
|
|
|
|
document.getElementById('yearRest').innerText = 600 - parseInt(yearData)
|
|
|
|
document.getElementById('yearRest').innerText = 600 - parseInt(yearData)
|
|
|
|
document.getElementById('prBarYear').style.width = `${Math.round((100/600)*parseInt(yearData))}%`
|
|
|
|
document.getElementById('prBarYear').style.width = `${Math.round((100/600)*parseInt(yearData))}%`
|
|
|
|
updateRule55Badge()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Fehler bei der Initialisierung oder Filterung:', error);
|
|
|
|
console.error('Fehler bei der Initialisierung oder Filterung:', error);
|
|
|
|
@ -663,7 +323,7 @@ document.getElementById('editEntrySubmitButton').addEventListener('click', () =>
|
|
|
|
|
|
|
|
|
|
|
|
updateEntry(parseInt(ToEditID), 'hours', {
|
|
|
|
updateEntry(parseInt(ToEditID), 'hours', {
|
|
|
|
date: document.getElementById('editDatum').value,
|
|
|
|
date: document.getElementById('editDatum').value,
|
|
|
|
duration: ((parseInt(edithours.value) || 0)*60) + parseInt(editMins.value),
|
|
|
|
duration: (parseInt(edithours.value)*60) + parseInt(editMins.value),
|
|
|
|
type: type,
|
|
|
|
type: type,
|
|
|
|
status: 1,
|
|
|
|
status: 1,
|
|
|
|
sondertext: document.getElementById('editsonstigesInput').value,
|
|
|
|
sondertext: document.getElementById('editsonstigesInput').value,
|
|
|
|
@ -689,22 +349,16 @@ document.getElementById('DeleteEntryButton').addEventListener('click', () => {
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
const monthEntrys = document.querySelectorAll('.monthEntrys');
|
|
|
|
const monthEntrys = document.querySelectorAll('.monthEntrys');
|
|
|
|
|
|
|
|
var diffMonth = 0
|
|
|
|
// Cursor für die Monatsnavigation: echtes Kalenderjahr + 0-basierter Monat (JS-Konvention).
|
|
|
|
|
|
|
|
// Startet auf dem aktuellen Monat/Jahr und wird bei Vor/Zurück direkt fortgeschrieben,
|
|
|
|
|
|
|
|
// unabhängig vom Dienstjahr-Label - dadurch keine künstliche Sperre mehr bei Sept/Aug.
|
|
|
|
|
|
|
|
var cursorMonth = new Date().getMonth();
|
|
|
|
|
|
|
|
var cursorYear = new Date().getFullYear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
document.getElementById('dashbord_month_area').addEventListener('click', () =>{
|
|
|
|
document.getElementById('dashbord_month_area').addEventListener('click', () =>{
|
|
|
|
if (!document.getElementById('dashbord_month_area').classList.contains('ActiveMonth')) {
|
|
|
|
if (!document.getElementById('dashbord_month_area').classList.contains('ActiveMonth')) {
|
|
|
|
document.getElementById('dashbord_month_area').classList.replace('closeMonthArea', 'openMonthArea')
|
|
|
|
document.getElementById('dashbord_month_area').classList.replace('closeMonthArea', 'openMonthArea')
|
|
|
|
document.getElementById('dashbord_month_area').classList.add(['openMonthArea'])
|
|
|
|
document.getElementById('dashbord_month_area').classList.add(['openMonthArea'])
|
|
|
|
document.getElementById('dashbord_month_area').classList.add(['ActiveMonth'])
|
|
|
|
document.getElementById('dashbord_month_area').classList.add(['ActiveMonth'])
|
|
|
|
// ActivitysTable ist jetzt flex:1 1 auto (siehe custom.css) und macht der wachsenden
|
|
|
|
document.getElementById('ActivitysTable').classList.add(['shrinkActivitys'])
|
|
|
|
// Monatskarte automatisch Platz - kein manuelles shrinkActivitys/growActivitys mehr nötig,
|
|
|
|
document.getElementById('ActivitysTable').classList.replace('growActivitys', 'shrinkActivitys')
|
|
|
|
// das würde der Flex-Berechnung sonst mit einer festen vh-Höhe in die Quere kommen.
|
|
|
|
document.getElementById('dashbord_month_area').classList.remove('mt-4')
|
|
|
|
document.getElementById('dashbord_month_area').classList.remove('mt-3')
|
|
|
|
|
|
|
|
// document.getElementById('dashbord_year_area').classList.add('fade-out')
|
|
|
|
// document.getElementById('dashbord_year_area').classList.add('fade-out')
|
|
|
|
// Für jedes ausgewählte Element die neue Klasse hinzufügen
|
|
|
|
// Für jedes ausgewählte Element die neue Klasse hinzufügen
|
|
|
|
setTimeout(function() {
|
|
|
|
setTimeout(function() {
|
|
|
|
@ -720,37 +374,37 @@ document.getElementById('dashbord_month_area').addEventListener('click', () =>{
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
document.getElementById('dashbord_month_area').classList.remove('ActiveMonth')
|
|
|
|
document.getElementById('dashbord_month_area').classList.remove('ActiveMonth')
|
|
|
|
document.getElementById('dashbord_month_area').classList.replace('openMonthArea', 'closeMonthArea')
|
|
|
|
document.getElementById('dashbord_month_area').classList.replace('openMonthArea', 'closeMonthArea')
|
|
|
|
document.getElementById('dashbord_month_area').classList.add('mt-3')
|
|
|
|
document.getElementById('ActivitysTable').classList.replace('shrinkActivitys', 'growActivitys')
|
|
|
|
monthEntrys.forEach(element => {
|
|
|
|
monthEntrys.forEach(element => {
|
|
|
|
element.classList.replace('fade-in', 'fade-out');
|
|
|
|
element.classList.replace('fade-in', 'fade-out');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
document.getElementById('MonthNameOfActual').innerHTML = "Monat:"
|
|
|
|
document.getElementById('MonthNameOfActual').innerHTML = "Monat:"
|
|
|
|
cursorMonth = new Date().getMonth();
|
|
|
|
// document.getElementById('actualMonthName').innerHTML = monate[new Date().getMonth()];
|
|
|
|
cursorYear = new Date().getFullYear();
|
|
|
|
diffMonth = 0;
|
|
|
|
getActualDataAndFillView(cursorMonth, cursorYear)
|
|
|
|
getActualDataAndFillView(new Date().getMonth() + diffMonth + 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
document.getElementById('btn-month-before').addEventListener('click', () =>{
|
|
|
|
document.getElementById('btn-month-before').addEventListener('click', () =>{
|
|
|
|
if (cursorMonth === 0) {
|
|
|
|
if (diffMonth === 0) {
|
|
|
|
// Januar -> Dezember des Vorjahres
|
|
|
|
diffMonth = 11;
|
|
|
|
cursorMonth = 11;
|
|
|
|
getActualDataAndFillView(new Date().getMonth() + diffMonth + 1)
|
|
|
|
cursorYear -= 1;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
cursorMonth -= 1;
|
|
|
|
diffMonth = ((monate[new Date().getMonth() + diffMonth]) != 'September') ? diffMonth - 1 : diffMonth;
|
|
|
|
}
|
|
|
|
// document.getElementById('actualMonthName').innerHTML = monate[new Date().getMonth() + diffMonth];
|
|
|
|
getActualDataAndFillView(cursorMonth, cursorYear)
|
|
|
|
getActualDataAndFillView(new Date().getMonth() + diffMonth + 1)
|
|
|
|
|
|
|
|
};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
document.getElementById('btn-month-next').addEventListener('click', () =>{
|
|
|
|
document.getElementById('btn-month-next').addEventListener('click', () =>{
|
|
|
|
if (cursorMonth === 11) {
|
|
|
|
if (diffMonth === 11) {
|
|
|
|
// Dezember -> Januar des Folgejahres
|
|
|
|
diffMonth = 0;
|
|
|
|
cursorMonth = 0;
|
|
|
|
getActualDataAndFillView(new Date().getMonth() + diffMonth + 1)
|
|
|
|
cursorYear += 1;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
cursorMonth += 1;
|
|
|
|
diffMonth = ((monate[new Date().getMonth() + diffMonth]) != 'August') ? diffMonth + 1 : diffMonth;
|
|
|
|
}
|
|
|
|
// document.getElementById('actualMonthName').innerHTML = monate[new Date().getMonth() + diffMonth];
|
|
|
|
getActualDataAndFillView(cursorMonth, cursorYear)
|
|
|
|
getActualDataAndFillView(new Date().getMonth() + diffMonth + 1)
|
|
|
|
|
|
|
|
};
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
function setNewCalsOfMonth(TheMonth) {
|
|
|
|
function setNewCalsOfMonth(TheMonth) {
|
|
|
|
@ -775,7 +429,7 @@ function checkInput() {
|
|
|
|
if ((sonstigesCheck.checked && sonstigesInput.value !== "") || !(sonstigesCheck.checked)) {
|
|
|
|
if ((sonstigesCheck.checked && sonstigesInput.value !== "") || !(sonstigesCheck.checked)) {
|
|
|
|
// Debug Ausgabe für Bedingungsstufen
|
|
|
|
// Debug Ausgabe für Bedingungsstufen
|
|
|
|
// console.log("Erste Bedingung: TRUE")
|
|
|
|
// console.log("Erste Bedingung: TRUE")
|
|
|
|
if (mins.value) { // Stunden sind optional, Minuten bleiben Pflicht
|
|
|
|
if (hours.value && mins.value) {
|
|
|
|
// Debug Ausgabe für Bedingungsstufen
|
|
|
|
// Debug Ausgabe für Bedingungsstufen
|
|
|
|
// console.log("Zweite Bedingung: TRUE")
|
|
|
|
// console.log("Zweite Bedingung: TRUE")
|
|
|
|
if (!allowToSend) {
|
|
|
|
if (!allowToSend) {
|
|
|
|
@ -815,7 +469,7 @@ function checkEditInput() {
|
|
|
|
if ((editsonstigesCheck.checked && editsonstigesInput.value !== "") || !(editsonstigesCheck.checked)) {
|
|
|
|
if ((editsonstigesCheck.checked && editsonstigesInput.value !== "") || !(editsonstigesCheck.checked)) {
|
|
|
|
// Debug Ausgabe für Bedingungsstufen
|
|
|
|
// Debug Ausgabe für Bedingungsstufen
|
|
|
|
// console.log("Erste Bedingung: TRUE")
|
|
|
|
// console.log("Erste Bedingung: TRUE")
|
|
|
|
if (editMins.value) { // Stunden sind optional, Minuten bleiben Pflicht
|
|
|
|
if (edithours.value && editMins.value) {
|
|
|
|
// Debug Ausgabe für Bedingungsstufen
|
|
|
|
// Debug Ausgabe für Bedingungsstufen
|
|
|
|
// console.log("Zweite Bedingung: TRUE")
|
|
|
|
// console.log("Zweite Bedingung: TRUE")
|
|
|
|
if (!editallowToSend) {
|
|
|
|
if (!editallowToSend) {
|