Compare commits
6 Commits
main
...
#2-Bericht
| Author | SHA1 | Date |
|---|---|---|
|
|
d6c590fdee | 2 months ago |
|
|
f0caaf7288 | 1 year ago |
|
|
0b3cb99431 | 1 year ago |
|
|
00bd28e0f0 | 1 year ago |
|
|
f2fbe0e8c1 | 1 year ago |
|
|
3c721a4dd8 | 2 years ago |
@ -1,12 +1,3 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import UsageEvent
|
# Register your models here.
|
||||||
|
|
||||||
|
|
||||||
@admin.register(UsageEvent)
|
|
||||||
class UsageEventAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ("device_id", "created_at", "app_version", "platform", "browser", "is_standalone")
|
|
||||||
list_filter = ("platform", "browser", "is_standalone", "app_version")
|
|
||||||
search_fields = ("device_id",)
|
|
||||||
date_hierarchy = "created_at"
|
|
||||||
ordering = ("-created_at",)
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 131 KiB |
@ -0,0 +1,500 @@
|
|||||||
|
// Absende Formular Verwalten
|
||||||
|
const hours = document.getElementById('stunden');
|
||||||
|
const mins = document.getElementById('minuten');
|
||||||
|
const NewEntryButton = document.getElementById('newEntrySubmitButton')
|
||||||
|
const SETStudySaveButton = document.getElementById('SETStudySaveButton')
|
||||||
|
const SETMonthGoalSaveButton = document.getElementById('SETMonthGoalSaveButton')
|
||||||
|
var allowToSend = false;
|
||||||
|
const monate = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"];
|
||||||
|
const currentDate = new Date();
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Trigger
|
||||||
|
//
|
||||||
|
|
||||||
|
// Wenn das Dokument komplett geladen ist
|
||||||
|
document.addEventListener('DOMContentLoaded', (event) => {
|
||||||
|
initDB().then(() => {
|
||||||
|
console.log('IndexedDB erfolgreich initialisiert.');
|
||||||
|
// Hier kannst du die App weiter initialisieren, z.B. Daten laden oder die UI aufbauen
|
||||||
|
|
||||||
|
// Bildschirm mit dem Inhalt für den aktuellen Tag füllen
|
||||||
|
getActualDataAndFillView();
|
||||||
|
|
||||||
|
//loadInitialData();
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error('Fehler bei der Initialisierung der IndexedDB:', error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Änderungen überwachen damit die das Formular nicht zu früh abgesendet wird
|
||||||
|
hours.addEventListener('input', () => {
|
||||||
|
checkInput();
|
||||||
|
})
|
||||||
|
mins.addEventListener('input', () => {
|
||||||
|
checkInput();
|
||||||
|
})
|
||||||
|
document.getElementById('sonstigesInput').addEventListener('input', () => {
|
||||||
|
checkInput();
|
||||||
|
})
|
||||||
|
|
||||||
|
// Einstellungen wenn Neuer Eintrag erstellt wird
|
||||||
|
NewEntryButton.addEventListener('click', () => {
|
||||||
|
|
||||||
|
if (allowToSend === true) {
|
||||||
|
var type = 1
|
||||||
|
|
||||||
|
// Abfragen der Checkboxen
|
||||||
|
const ldcCheck = document.getElementById('ldcCheck').checked
|
||||||
|
if (ldcCheck) {
|
||||||
|
type = 2
|
||||||
|
document.getElementById('ldcCheck').checked = false
|
||||||
|
} else if (document.getElementById('sonstigesCheck').checked) {
|
||||||
|
type = 3;
|
||||||
|
document.getElementById('sonstigesCheck').checked = false;
|
||||||
|
sonstigesText.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Berechnen der Duration
|
||||||
|
const duration = (parseInt(hours.value)*60) + parseInt(mins.value)
|
||||||
|
|
||||||
|
const newEntryData = {
|
||||||
|
date: document.getElementById('datum').value,
|
||||||
|
duration: duration,
|
||||||
|
type: type,
|
||||||
|
status: 1,
|
||||||
|
sondertext: document.getElementById('sonstigesInput').value,
|
||||||
|
}
|
||||||
|
|
||||||
|
addEntry(newEntryData, 'hours').then((id) => {
|
||||||
|
// console.log('Eintrag hinzugefügt mit ID:', id);
|
||||||
|
location.reload()
|
||||||
|
});
|
||||||
|
|
||||||
|
hours.value = null
|
||||||
|
mins.value = null
|
||||||
|
document.getElementById('sonstigesInput').value = null
|
||||||
|
checkInput()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// SETTINGS ACTIONS
|
||||||
|
|
||||||
|
SETStudySaveButton.addEventListener('click', () => {
|
||||||
|
|
||||||
|
var actualSettings = 0
|
||||||
|
|
||||||
|
getAllEntries('settings')
|
||||||
|
.then(function(result) {
|
||||||
|
const SETDBData = result.find(element => element.SettingsID === 1)
|
||||||
|
actualSettingsEntryID = SETDBData ? SETDBData.id : undefined;
|
||||||
|
actualSettings = SETDBData ? SETDBData.SettingsValue : undefined;
|
||||||
|
|
||||||
|
// AKTUELLE DATEN AUS FELD ÜBERNHEMEN
|
||||||
|
var ActInput = document.getElementById('studysinput').value
|
||||||
|
|
||||||
|
const StudySettingsData = {
|
||||||
|
SettingsID: 1,
|
||||||
|
SettingsValue: parseInt(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', StudySettingsData)
|
||||||
|
} else {
|
||||||
|
addEntry(StudySettingsData, 'settings')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
SETStudySaveButton.classList.add('d-none')
|
||||||
|
})
|
||||||
|
|
||||||
|
SETMonthGoalSaveButton.addEventListener('click', () => {
|
||||||
|
getAllEntries('settings')
|
||||||
|
.then(function(result){
|
||||||
|
|
||||||
|
const SETDBData = result.find(element => element.SettingsID === 2)
|
||||||
|
actualSettingsEntryID = SETDBData ? SETDBData.id : undefined;
|
||||||
|
actualSettings = SETDBData ? SETDBData.SettingsValue : undefined;
|
||||||
|
|
||||||
|
// AKTUELLE DATEN AUS FELD ÜBERNHEMEN
|
||||||
|
var ActInput = document.getElementById('MonthGoalInput').value
|
||||||
|
|
||||||
|
const StudySettingsData = {
|
||||||
|
SettingsID: 2,
|
||||||
|
SettingsValue: parseInt(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', StudySettingsData)
|
||||||
|
} else {
|
||||||
|
addEntry(StudySettingsData, 'settings')
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPDATE DER MONATSANSICHT
|
||||||
|
|
||||||
|
// Aktueller Monatsstand an Stunden
|
||||||
|
const GesamtStundenMonat = parseInt(document.getElementById('MonthSumHours').value)
|
||||||
|
document.getElementById('monthHours').innerText = GesamtStundenMonat + "/" + parseInt(ActInput)
|
||||||
|
document.getElementById('prBarMonth').style.width = `${(100/parseInt(ActInput))*parseInt(GesamtStundenMonat)}%`
|
||||||
|
|
||||||
|
// Aktueller Rest an Stunden
|
||||||
|
const rest = parseInt(ActInput) - parseInt(GesamtStundenMonat)
|
||||||
|
if (rest > 0) {
|
||||||
|
document.getElementById('monthRest').innerText = rest
|
||||||
|
} else {
|
||||||
|
document.getElementById('monthRest').innerText = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
SETMonthGoalSaveButton.classList.add('d-none')
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
async function getActualDataAndFillView(monat = currentDate.getMonth(), jahr = currentDate.getFullYear()) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Einfüfen des aktuellen Monats
|
||||||
|
document.getElementById('actualMonthName').innerHTML = monate[monat !== 12 ? monat : 0];
|
||||||
|
console.log("AKTUELLER MONAT SYSTEM: ", monat)
|
||||||
|
console.log("AKTUELLER MONAT REAL: ", currentDate.getMonth())
|
||||||
|
|
||||||
|
// Settings vor ausfüllen
|
||||||
|
|
||||||
|
// Monatswunsch-Stunden Abfragen
|
||||||
|
var MonthGoal = 50
|
||||||
|
|
||||||
|
// DATEN VON SETTINGS ABFRAGEN
|
||||||
|
getAllEntries('settings')
|
||||||
|
.then(function(result) {
|
||||||
|
document.getElementById('studysinput').value = (result.find(element => element.SettingsID === 1) == undefined) ? 0 : parseInt(result.find(element => element.SettingsID === 1).SettingsValue)
|
||||||
|
document.getElementById('MonthGoalInput').value = (result.find(element => element.SettingsID === 2) == undefined) ? 50 : parseInt(result.find(element => element.SettingsID === 2).SettingsValue)
|
||||||
|
MonthGoal = (result.find(element => element.SettingsID === 2) == undefined) ? 50 : parseInt(result.find(element => element.SettingsID === 2).SettingsValue)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter funktion aufrufen und entsprechend mit dem aktuellen Datum füllen
|
||||||
|
const filteredEntries = await filterEntriesByMonthYear(monat === 12 ? 1 : monat + 1, jahr);
|
||||||
|
|
||||||
|
// Tabelle mit den aktuellen informationen füllen (funktion triggern und Daten übergeben)
|
||||||
|
fillTableWithEntries(filteredEntries)
|
||||||
|
|
||||||
|
// Ausgabe der Daten in den Log für DEV möglich
|
||||||
|
// console.log('Gefilterte Einträge für September 2024:', filteredEntries);
|
||||||
|
|
||||||
|
// MonatsCard füllen
|
||||||
|
|
||||||
|
// Aktueller Monatsstand an Stunden
|
||||||
|
const GesamtStundenMonat = formatDuration(sumDurations(filteredEntries,null,true), true)
|
||||||
|
document.getElementById('monthHours').innerText = GesamtStundenMonat + "/" + MonthGoal
|
||||||
|
document.getElementById('prBarMonth').style.width = `${(100/MonthGoal)*parseInt(GesamtStundenMonat)}%`
|
||||||
|
document.getElementById('MonthSumHours').value = GesamtStundenMonat
|
||||||
|
|
||||||
|
// Aktueller Rest an Stunden
|
||||||
|
const rest = MonthGoal - parseInt(GesamtStundenMonat)
|
||||||
|
if (rest > 0) {
|
||||||
|
document.getElementById('monthRest').innerText = rest
|
||||||
|
} else {
|
||||||
|
document.getElementById('monthRest').innerText = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aufteilunge Stunden nach Dienst und LDC
|
||||||
|
document.getElementById('monthHourService').innerText = formatDuration(sumDurations(filteredEntries,1,true), true)
|
||||||
|
document.getElementById('monthHourLDC').innerText = formatDuration(sumDurations(filteredEntries,2,true), true)
|
||||||
|
document.getElementById('monthHourOther').innerText = formatDuration(sumDurations(filteredEntries,3,true), true)
|
||||||
|
|
||||||
|
// Jahres Ansicht füllen
|
||||||
|
var requestYear = currentDate.getFullYear()
|
||||||
|
if (currentDate.getMonth() +1 >= 9) {
|
||||||
|
requestYear += 1;
|
||||||
|
}
|
||||||
|
var yearData = await filterEntriesByMonthYear(null, requestYear)
|
||||||
|
yearData = formatDuration(sumDurations(yearData, null, true), true)
|
||||||
|
document.getElementById('yearHours').innerText = yearData
|
||||||
|
document.getElementById('yearRest').innerText = 600 - parseInt(yearData)
|
||||||
|
document.getElementById('prBarYear').style.width = `${Math.round((100/600)*parseInt(yearData))}%`
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Fehler bei der Initialisierung oder Filterung:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// NEUES EINTRAG FORMULAR
|
||||||
|
//
|
||||||
|
|
||||||
|
// Checkboxen-Verhalten: Nur eine Checkbox kann ausgewählt werden
|
||||||
|
var ldcCheck = document.getElementById('ldcCheck');
|
||||||
|
var sonstigesCheck = document.getElementById('sonstigesCheck');
|
||||||
|
var sonstigesText = document.getElementById('sonstiges-text');
|
||||||
|
var sonstigesInput = document.getElementById('sonstigesInput');
|
||||||
|
|
||||||
|
ldcCheck.addEventListener('change', function() {
|
||||||
|
if (ldcCheck.checked) {
|
||||||
|
sonstigesCheck.checked = false;
|
||||||
|
sonstigesText.style.display = 'none';
|
||||||
|
sonstigesInput.removeAttribute('required'); // Entferne required, wenn "Sonstiges" abgewählt ist
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sonstigesCheck.addEventListener('change', function() {
|
||||||
|
checkInput();
|
||||||
|
if (sonstigesCheck.checked) {
|
||||||
|
ldcCheck.checked = false;
|
||||||
|
sonstigesText.style.display = 'block';
|
||||||
|
sonstigesInput.setAttribute('required', 'required'); // Setze required, wenn "Sonstiges" ausgewählt ist
|
||||||
|
} else {
|
||||||
|
sonstigesText.style.display = 'none';
|
||||||
|
sonstigesInput.removeAttribute('required'); // Entferne required, wenn "Sonstiges" abgewählt ist
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// BEARBEITUNGS FORMULAR
|
||||||
|
//
|
||||||
|
|
||||||
|
var edithours = document.getElementById('editStunden')
|
||||||
|
var editMins = document.getElementById('editMinuten')
|
||||||
|
var editldcCheck = document.getElementById('editldcCheck');
|
||||||
|
var editsonstigesCheck = document.getElementById('editsonstigesCheck');
|
||||||
|
var editsonstigesText = document.getElementById('edit-sonstiges-text');
|
||||||
|
var editsonstigesInput = document.getElementById('editsonstigesInput');
|
||||||
|
var EditSaveButton = document.getElementById('editEntrySubmitButton');
|
||||||
|
|
||||||
|
|
||||||
|
// Änderungen überwachen damit die das Formular nicht zu früh abgesendet wird
|
||||||
|
edithours.addEventListener('input', () => {
|
||||||
|
checkEditInput();
|
||||||
|
console.log(this.value)
|
||||||
|
})
|
||||||
|
editMins.addEventListener('input', () => {
|
||||||
|
checkEditInput();
|
||||||
|
console.log(this.value)
|
||||||
|
})
|
||||||
|
editsonstigesInput.addEventListener('input', () => {
|
||||||
|
checkEditInput();
|
||||||
|
console.log(this.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
editldcCheck.addEventListener('change', function() {
|
||||||
|
if (editldcCheck.checked) {
|
||||||
|
editsonstigesCheck.checked = false;
|
||||||
|
editsonstigesText.style.display = 'none';
|
||||||
|
editsonstigesInput.removeAttribute('required'); // Entferne required, wenn "Sonstiges" abgewählt ist
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
editsonstigesCheck.addEventListener('change', function() {
|
||||||
|
checkEditInput();
|
||||||
|
if (editsonstigesCheck.checked) {
|
||||||
|
editldcCheck.checked = false;
|
||||||
|
editsonstigesText.style.display = 'block';
|
||||||
|
editsonstigesInput.setAttribute('required', 'required'); // Setze required, wenn "Sonstiges" ausgewählt ist
|
||||||
|
} else {
|
||||||
|
editsonstigesText.style.display = 'none';
|
||||||
|
editsonstigesInput.removeAttribute('required'); // Entferne required, wenn "Sonstiges" abgewählt ist
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById('editEntrySubmitButton').addEventListener('click', () => {
|
||||||
|
var ToEditID = document.getElementById('editEntryID').value
|
||||||
|
// console.log(`ID: ${ToEditID}, Hours: ${editHours.values}, Minutes: ${editMins.values}`)
|
||||||
|
|
||||||
|
var type = 1
|
||||||
|
|
||||||
|
// Abfragen der Checkboxen
|
||||||
|
const ldcCheck = document.getElementById('editldcCheck').checked
|
||||||
|
if (ldcCheck) {
|
||||||
|
type = 2
|
||||||
|
document.getElementById('editldcCheck').checked = false
|
||||||
|
} else if (document.getElementById('editsonstigesCheck').checked) {
|
||||||
|
type = 3;
|
||||||
|
document.getElementById('editsonstigesCheck').checked = false;
|
||||||
|
sonstigesText.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
updateEntry(parseInt(ToEditID), 'hours', {
|
||||||
|
date: document.getElementById('editDatum').value,
|
||||||
|
duration: (parseInt(edithours.value)*60) + parseInt(editMins.value),
|
||||||
|
type: type,
|
||||||
|
status: 1,
|
||||||
|
sondertext: document.getElementById('editsonstigesInput').value,
|
||||||
|
}).then(() => {
|
||||||
|
// console.log('Eintrag aktualisiert.');
|
||||||
|
location.reload()
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById('DeleteEntryButton').addEventListener('click', () => {
|
||||||
|
const ToEditID = document.getElementById('editEntryID').value
|
||||||
|
|
||||||
|
deleteEntry(parseInt(ToEditID)).then(() => {
|
||||||
|
console.log(`Löschen von Eintrag: ${ToEditID}`);
|
||||||
|
location.reload()
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// MONATSANSICHT Anpassen
|
||||||
|
//
|
||||||
|
|
||||||
|
const monthEntrys = document.querySelectorAll('.monthEntrys');
|
||||||
|
var diffMonth = 0
|
||||||
|
|
||||||
|
document.getElementById('dashbord_month_area').addEventListener('click', () =>{
|
||||||
|
if (!document.getElementById('dashbord_month_area').classList.contains('ActiveMonth')) {
|
||||||
|
document.getElementById('dashbord_month_area').classList.replace('closeMonthArea', 'openMonthArea')
|
||||||
|
document.getElementById('dashbord_month_area').classList.add(['openMonthArea'])
|
||||||
|
document.getElementById('dashbord_month_area').classList.add(['ActiveMonth'])
|
||||||
|
document.getElementById('ActivitysTable').classList.add(['shrinkActivitys'])
|
||||||
|
document.getElementById('ActivitysTable').classList.replace('growActivitys', 'shrinkActivitys')
|
||||||
|
document.getElementById('dashbord_month_area').classList.remove('mt-4')
|
||||||
|
// document.getElementById('dashbord_year_area').classList.add('fade-out')
|
||||||
|
// Für jedes ausgewählte Element die neue Klasse hinzufügen
|
||||||
|
setTimeout(function() {
|
||||||
|
monthEntrys.forEach(element => {
|
||||||
|
if (element.classList.contains('fade-out')) {
|
||||||
|
element.classList.replace('fade-out', 'fade-in');
|
||||||
|
} else {
|
||||||
|
element.classList.add('fade-in');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.getElementById('MonthNameOfActual').innerHTML = "Aktuell:"
|
||||||
|
}, 300);
|
||||||
|
} else {
|
||||||
|
document.getElementById('dashbord_month_area').classList.remove('ActiveMonth')
|
||||||
|
document.getElementById('dashbord_month_area').classList.replace('openMonthArea', 'closeMonthArea')
|
||||||
|
document.getElementById('ActivitysTable').classList.replace('shrinkActivitys', 'growActivitys')
|
||||||
|
monthEntrys.forEach(element => {
|
||||||
|
element.classList.replace('fade-in', 'fade-out');
|
||||||
|
});
|
||||||
|
document.getElementById('MonthNameOfActual').innerHTML = "Monat:"
|
||||||
|
// document.getElementById('actualMonthName').innerHTML = monate[new Date().getMonth()];
|
||||||
|
diffMonth = 0;
|
||||||
|
getActualDataAndFillView(new Date().getMonth() + diffMonth)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById('btn-month-before').addEventListener('click', () =>{
|
||||||
|
console.log("CLICK-BEFORE: ", diffMonth)
|
||||||
|
if (new Date().getMonth() + diffMonth == 0) {
|
||||||
|
diffMonth = 11 - new Date().getMonth();
|
||||||
|
getActualDataAndFillView(new Date().getMonth() + diffMonth)
|
||||||
|
console.log("CLICK-BEFRORE-0TO11: ", diffMonth)
|
||||||
|
} else {
|
||||||
|
diffMonth = ((monate[new Date().getMonth() + diffMonth]) != 'September') ? diffMonth - 1 : diffMonth;
|
||||||
|
// document.getElementById('actualMonthName').innerHTML = monate[new Date().getMonth() + diffMonth];
|
||||||
|
getActualDataAndFillView(new Date().getMonth() + diffMonth)
|
||||||
|
};
|
||||||
|
console.log("CLICK-BEFORE-AFTER: ", diffMonth)
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('btn-month-next').addEventListener('click', () =>{
|
||||||
|
console.log("CLICK-NEXT: ", diffMonth)
|
||||||
|
if (new Date().getMonth() + diffMonth == 11) {
|
||||||
|
diffMonth = 0 - new Date().getMonth();
|
||||||
|
getActualDataAndFillView(new Date().getMonth() + diffMonth)
|
||||||
|
console.log("CLICK-NEXT-11TO0: ", diffMonth)
|
||||||
|
} else {
|
||||||
|
diffMonth = ((monate[new Date().getMonth() + diffMonth]) != 'August') ? diffMonth + 1 : diffMonth;
|
||||||
|
// document.getElementById('actualMonthName').innerHTML = monate[new Date().getMonth() + diffMonth];
|
||||||
|
getActualDataAndFillView(new Date().getMonth() + diffMonth)
|
||||||
|
};
|
||||||
|
console.log("CLICK-NEXT-AFTER: ", diffMonth)
|
||||||
|
})
|
||||||
|
|
||||||
|
function setNewCalsOfMonth(TheMonth) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNKTIONEN LIBARY
|
||||||
|
//
|
||||||
|
|
||||||
|
function checkInput() {
|
||||||
|
// Eingabe feld für Beschreibung leeren wenn sonstiges abgewählt wird
|
||||||
|
if (!sonstigesCheck.checked) {
|
||||||
|
sonstigesInput.value = null;
|
||||||
|
}
|
||||||
|
// Debug ausgabe er Werte
|
||||||
|
// console.log(`Check: ${sonstigesCheck.checked} - Input: ${sonstigesInput.value} - Stunden: ${hours.value} - Min: ${mins.value}`)
|
||||||
|
|
||||||
|
// Berechtigungen durch gehen damit Button verfügbar und Form abgesendet werden kann
|
||||||
|
if ((sonstigesCheck.checked && sonstigesInput.value !== "") || !(sonstigesCheck.checked)) {
|
||||||
|
// Debug Ausgabe für Bedingungsstufen
|
||||||
|
// console.log("Erste Bedingung: TRUE")
|
||||||
|
if (hours.value && mins.value) {
|
||||||
|
// Debug Ausgabe für Bedingungsstufen
|
||||||
|
// console.log("Zweite Bedingung: TRUE")
|
||||||
|
if (!allowToSend) {
|
||||||
|
// Debug Ausgabe für Bedingungsstufen
|
||||||
|
// console.log("Dritte Bedingung: TRUE")
|
||||||
|
allowToSend = true;
|
||||||
|
NewEntryButton.classList.remove('disabled');
|
||||||
|
NewEntryButton.classList.replace('btn-light', 'btn-primary');
|
||||||
|
}
|
||||||
|
} else if (allowToSend) {
|
||||||
|
allowToSend = false;
|
||||||
|
NewEntryButton.classList.add('disabled');
|
||||||
|
NewEntryButton.classList.replace('btn-primary', 'btn-light');
|
||||||
|
}
|
||||||
|
} else if (allowToSend) {
|
||||||
|
allowToSend = false;
|
||||||
|
NewEntryButton.classList.add('disabled');
|
||||||
|
NewEntryButton.classList.replace('btn-primary', 'btn-light');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var editallowToSend = true;
|
||||||
|
function checkEditInput() {
|
||||||
|
var edithours = document.getElementById('editStunden')
|
||||||
|
var editMins = document.getElementById('editMinuten')
|
||||||
|
var editsonstigesCheck = document.getElementById('editsonstigesCheck');
|
||||||
|
var editsonstigesText = document.getElementById('edit-sonstiges-text');
|
||||||
|
var editsonstigesInput = document.getElementById('editsonstigesInput');
|
||||||
|
var EditSaveButton = document.getElementById('editEntrySubmitButton');
|
||||||
|
|
||||||
|
// Eingabe feld für Beschreibung leeren wenn sonstiges abgewählt wird
|
||||||
|
if (!editsonstigesCheck.checked) {
|
||||||
|
editsonstigesInput.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Berechtigungen durch gehen damit Button verfügbar und Form abgesendet werden kann
|
||||||
|
if ((editsonstigesCheck.checked && editsonstigesInput.value !== "") || !(editsonstigesCheck.checked)) {
|
||||||
|
// Debug Ausgabe für Bedingungsstufen
|
||||||
|
// console.log("Erste Bedingung: TRUE")
|
||||||
|
if (edithours.value && editMins.value) {
|
||||||
|
// Debug Ausgabe für Bedingungsstufen
|
||||||
|
// console.log("Zweite Bedingung: TRUE")
|
||||||
|
if (!editallowToSend) {
|
||||||
|
// Debug Ausgabe für Bedingungsstufen
|
||||||
|
// console.log("Dritte Bedingung: TRUE")
|
||||||
|
editallowToSend = true;
|
||||||
|
EditSaveButton.classList.remove('disabled');
|
||||||
|
EditSaveButton.classList.replace('btn-light', 'btn-primary');
|
||||||
|
}
|
||||||
|
} else if (editallowToSend) {
|
||||||
|
editallowToSend = false;
|
||||||
|
EditSaveButton.classList.add('disabled');
|
||||||
|
EditSaveButton.classList.replace('btn-primary', 'btn-light');
|
||||||
|
}
|
||||||
|
} else if (editallowToSend) {
|
||||||
|
editallowToSend = false;
|
||||||
|
EditSaveButton.classList.add('disabled');
|
||||||
|
EditSaveButton.classList.replace('btn-primary', 'btn-light');
|
||||||
|
}
|
||||||
|
// Debug ausgabe er Werte
|
||||||
|
console.log(`Status: ${editallowToSend} - Check: ${editsonstigesCheck.checked} - Input: ${editsonstigesInput.value} - Stunden: ${edithours.value} - Min: ${editMinuten.value}`)
|
||||||
|
}
|
||||||
@ -1,906 +0,0 @@
|
|||||||
// Absende Formular Verwalten
|
|
||||||
const hours = document.getElementById('stunden');
|
|
||||||
const mins = document.getElementById('minuten');
|
|
||||||
const NewEntryButton = document.getElementById('newEntrySubmitButton')
|
|
||||||
const SETStudySaveButton = document.getElementById('SETStudySaveButton')
|
|
||||||
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;
|
|
||||||
const monate = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"];
|
|
||||||
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
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
// ANONYME NUTZUNGSSTATISTIK (Admin-Dashboard)
|
|
||||||
//
|
|
||||||
|
|
||||||
// Liest die zufällige Geräte-ID aus dem localStorage oder legt einmalig eine neue an.
|
|
||||||
// Kein Bezug zu einer Person - rein lokal generiert, dient nur der Dashboard-Zählung.
|
|
||||||
function getOrCreateDeviceId() {
|
|
||||||
try {
|
|
||||||
let id = localStorage.getItem('piomintDeviceId')
|
|
||||||
if (!id) {
|
|
||||||
id = (window.crypto && crypto.randomUUID) ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(16).slice(2)}`
|
|
||||||
localStorage.setItem('piomintDeviceId', id)
|
|
||||||
}
|
|
||||||
return id
|
|
||||||
} catch (error) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Meldet höchstens einmal pro Gerät und Tag ein anonymes "App genutzt"-Signal ans Backend.
|
|
||||||
// Darf die App unter keinen Umständen blockieren oder zum Absturz bringen - daher überall try/catch.
|
|
||||||
function pingUsageIfNeeded() {
|
|
||||||
try {
|
|
||||||
const today = new Date().toISOString().slice(0, 10)
|
|
||||||
if (localStorage.getItem('piomintLastPing') === today) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const deviceId = getOrCreateDeviceId()
|
|
||||||
if (!deviceId) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const standalone = (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches) || window.navigator.standalone === true
|
|
||||||
|
|
||||||
fetch('/app/track/', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({
|
|
||||||
device_id: deviceId,
|
|
||||||
app_version: document.body.dataset.appVersion || '',
|
|
||||||
standalone: standalone,
|
|
||||||
}),
|
|
||||||
}).then(() => {
|
|
||||||
localStorage.setItem('piomintLastPing', today)
|
|
||||||
}).catch(() => {
|
|
||||||
// Kein Netz/Fehler beim Tracking - einfach beim nächsten Öffnen erneut versuchen
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Nutzungssignal konnte nicht gesendet werden:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wenn das Dokument komplett geladen ist
|
|
||||||
document.addEventListener('DOMContentLoaded', (event) => {
|
|
||||||
pingUsageIfNeeded()
|
|
||||||
|
|
||||||
initDB().then(async () => {
|
|
||||||
console.log('IndexedDB erfolgreich initialisiert.');
|
|
||||||
// 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
|
|
||||||
getActualDataAndFillView();
|
|
||||||
|
|
||||||
//loadInitialData();
|
|
||||||
}).catch((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
|
|
||||||
hours.addEventListener('input', () => {
|
|
||||||
checkInput();
|
|
||||||
})
|
|
||||||
mins.addEventListener('input', () => {
|
|
||||||
checkInput();
|
|
||||||
})
|
|
||||||
document.getElementById('sonstigesInput').addEventListener('input', () => {
|
|
||||||
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
|
|
||||||
NewEntryButton.addEventListener('click', () => {
|
|
||||||
|
|
||||||
if (allowToSend === true) {
|
|
||||||
var type = 1
|
|
||||||
|
|
||||||
// Abfragen der Checkboxen
|
|
||||||
const ldcCheck = document.getElementById('ldcCheck').checked
|
|
||||||
if (ldcCheck) {
|
|
||||||
type = 2
|
|
||||||
document.getElementById('ldcCheck').checked = false
|
|
||||||
} else if (document.getElementById('sonstigesCheck').checked) {
|
|
||||||
type = 3;
|
|
||||||
document.getElementById('sonstigesCheck').checked = false;
|
|
||||||
sonstigesText.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Berechnen der Duration (Stunden sind optional -> ohne Eingabe wird 0 gespeichert)
|
|
||||||
const duration = ((parseInt(hours.value) || 0)*60) + (parseInt(mins.value) || 0)
|
|
||||||
|
|
||||||
const newEntryData = {
|
|
||||||
date: document.getElementById('datum').value,
|
|
||||||
duration: duration,
|
|
||||||
type: type,
|
|
||||||
status: 1,
|
|
||||||
sondertext: document.getElementById('sonstigesInput').value,
|
|
||||||
partner: document.getElementById('partnerInput').value.trim(),
|
|
||||||
}
|
|
||||||
|
|
||||||
addEntry(newEntryData, 'hours').then((id) => {
|
|
||||||
// console.log('Eintrag hinzugefügt mit ID:', id);
|
|
||||||
location.reload()
|
|
||||||
});
|
|
||||||
|
|
||||||
hours.value = null
|
|
||||||
mins.value = null
|
|
||||||
document.getElementById('sonstigesInput').value = null
|
|
||||||
document.getElementById('partnerInput').value = null
|
|
||||||
checkInput()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// SETTINGS ACTIONS
|
|
||||||
|
|
||||||
SETStudySaveButton.addEventListener('click', () => {
|
|
||||||
|
|
||||||
var actualSettings = 0
|
|
||||||
|
|
||||||
getAllEntries('settings')
|
|
||||||
.then(function(result) {
|
|
||||||
const SETDBData = result.find(element => element.SettingsID === 1)
|
|
||||||
actualSettingsEntryID = SETDBData ? SETDBData.id : undefined;
|
|
||||||
actualSettings = SETDBData ? SETDBData.SettingsValue : undefined;
|
|
||||||
|
|
||||||
// AKTUELLE DATEN AUS FELD ÜBERNHEMEN
|
|
||||||
var ActInput = document.getElementById('studysinput').value
|
|
||||||
|
|
||||||
const StudySettingsData = {
|
|
||||||
SettingsID: 1,
|
|
||||||
SettingsValue: parseInt(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', StudySettingsData)
|
|
||||||
} else {
|
|
||||||
addEntry(StudySettingsData, 'settings')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
SETStudySaveButton.classList.add('d-none')
|
|
||||||
})
|
|
||||||
|
|
||||||
SETMonthGoalSaveButton.addEventListener('click', () => {
|
|
||||||
getAllEntries('settings')
|
|
||||||
.then(function(result){
|
|
||||||
|
|
||||||
const SETDBData = result.find(element => element.SettingsID === 2)
|
|
||||||
actualSettingsEntryID = SETDBData ? SETDBData.id : undefined;
|
|
||||||
actualSettings = SETDBData ? SETDBData.SettingsValue : undefined;
|
|
||||||
|
|
||||||
// AKTUELLE DATEN AUS FELD ÜBERNHEMEN
|
|
||||||
var ActInput = document.getElementById('MonthGoalInput').value
|
|
||||||
|
|
||||||
const StudySettingsData = {
|
|
||||||
SettingsID: 2,
|
|
||||||
SettingsValue: parseInt(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', StudySettingsData)
|
|
||||||
} else {
|
|
||||||
addEntry(StudySettingsData, 'settings')
|
|
||||||
}
|
|
||||||
|
|
||||||
// UPDATE DER MONATSANSICHT
|
|
||||||
|
|
||||||
// Aktueller Monatsstand an Stunden
|
|
||||||
const GesamtStundenMonat = parseInt(document.getElementById('MonthSumHours').value)
|
|
||||||
document.getElementById('monthHours').innerText = GesamtStundenMonat + "/" + parseInt(ActInput)
|
|
||||||
document.getElementById('prBarMonth').style.width = `${(100/parseInt(ActInput))*parseInt(GesamtStundenMonat)}%`
|
|
||||||
|
|
||||||
// Aktueller Rest an Stunden
|
|
||||||
const rest = parseInt(ActInput) - parseInt(GesamtStundenMonat)
|
|
||||||
if (rest > 0) {
|
|
||||||
document.getElementById('monthRest').innerText = rest
|
|
||||||
} else {
|
|
||||||
document.getElementById('monthRest').innerText = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
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`
|
|
||||||
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 {
|
|
||||||
|
|
||||||
// Einfüfen des aktuellen Monats
|
|
||||||
document.getElementById('actualMonthName').innerHTML = monate[monat !== 12 ? monat : 0];
|
|
||||||
console.log("AKTUELLER MONAT SYSTEM: ", monat)
|
|
||||||
console.log("AKTUELLER MONAT REAL: ", currentDate.getMonth())
|
|
||||||
|
|
||||||
// Settings vor ausfüllen
|
|
||||||
|
|
||||||
// Monatswunsch-Stunden Abfragen
|
|
||||||
var MonthGoal = 50
|
|
||||||
|
|
||||||
// DATEN VON SETTINGS ABFRAGEN
|
|
||||||
getAllEntries('settings')
|
|
||||||
.then(function(result) {
|
|
||||||
document.getElementById('studysinput').value = (result.find(element => element.SettingsID === 1) == undefined) ? 0 : parseInt(result.find(element => element.SettingsID === 1).SettingsValue)
|
|
||||||
document.getElementById('MonthGoalInput').value = (result.find(element => element.SettingsID === 2) == undefined) ? 50 : parseInt(result.find(element => element.SettingsID === 2).SettingsValue)
|
|
||||||
MonthGoal = (result.find(element => element.SettingsID === 2) == undefined) ? 50 : parseInt(result.find(element => element.SettingsID === 2).SettingsValue)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Filter funktion aufrufen und entsprechend mit dem aktuellen Datum füllen
|
|
||||||
const filteredEntries = await filterEntriesByMonthYear(monat === 12 ? 1 : monat + 1, jahr);
|
|
||||||
currentMonthEntries = filteredEntries
|
|
||||||
|
|
||||||
console.log("update-complete")
|
|
||||||
console.log(jahr)
|
|
||||||
|
|
||||||
// Tabelle mit den aktuellen informationen füllen (funktion triggern und Daten übergeben)
|
|
||||||
fillTableWithEntries(filteredEntries, sortField, sortDirection, ldcLabel)
|
|
||||||
|
|
||||||
// Ausgabe der Daten in den Log für DEV möglich
|
|
||||||
// console.log('Gefilterte Einträge für September 2024:', filteredEntries);
|
|
||||||
|
|
||||||
// MonatsCard füllen
|
|
||||||
|
|
||||||
// Aktueller Monatsstand an Stunden
|
|
||||||
const GesamtStundenMonat = formatDuration(sumDurations(filteredEntries,null,true), true)
|
|
||||||
document.getElementById('monthHours').innerText = GesamtStundenMonat + "/" + MonthGoal
|
|
||||||
document.getElementById('prBarMonth').style.width = `${(100/MonthGoal)*parseInt(GesamtStundenMonat)}%`
|
|
||||||
document.getElementById('MonthSumHours').value = GesamtStundenMonat
|
|
||||||
|
|
||||||
// Aktueller Rest an Stunden
|
|
||||||
const rest = MonthGoal - parseInt(GesamtStundenMonat)
|
|
||||||
if (rest > 0) {
|
|
||||||
document.getElementById('monthRest').innerText = rest
|
|
||||||
} else {
|
|
||||||
document.getElementById('monthRest').innerText = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Aufteilunge Stunden nach Dienst und LDC
|
|
||||||
document.getElementById('monthHourService').innerText = formatDuration(sumDurations(filteredEntries,1,true), true)
|
|
||||||
document.getElementById('monthHourLDC').innerText = formatDuration(sumDurations(filteredEntries,2,true), true)
|
|
||||||
document.getElementById('monthHourOther').innerText = formatDuration(sumDurations(filteredEntries,3,true), true)
|
|
||||||
|
|
||||||
// Jahres Ansicht füllen (Dienstjahr, gekoppelt an den gerade angezeigten Monat/Jahr)
|
|
||||||
// Bei aktiver 55h-Regel wird jeder Monat mit LDC/Sonstiges-Anteil auf max. 55h gedeckelt,
|
|
||||||
// reine Dienststunden zählen dabei immer voll (siehe calculateServiceYearTotal).
|
|
||||||
var requestServiceYear = getServiceYear(new Date(jahr, monat, 1));
|
|
||||||
var yearEntries = await filterEntriesByServiceYear(requestServiceYear)
|
|
||||||
var yearData = formatDuration(calculateServiceYearTotal(yearEntries, rule55Active), true)
|
|
||||||
document.getElementById('yearHours').innerText = yearData
|
|
||||||
document.getElementById('yearRest').innerText = 600 - parseInt(yearData)
|
|
||||||
document.getElementById('prBarYear').style.width = `${Math.round((100/600)*parseInt(yearData))}%`
|
|
||||||
updateRule55Badge()
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Fehler bei der Initialisierung oder Filterung:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// NEUES EINTRAG FORMULAR
|
|
||||||
//
|
|
||||||
|
|
||||||
// Checkboxen-Verhalten: Nur eine Checkbox kann ausgewählt werden
|
|
||||||
var ldcCheck = document.getElementById('ldcCheck');
|
|
||||||
var sonstigesCheck = document.getElementById('sonstigesCheck');
|
|
||||||
var sonstigesText = document.getElementById('sonstiges-text');
|
|
||||||
var sonstigesInput = document.getElementById('sonstigesInput');
|
|
||||||
|
|
||||||
ldcCheck.addEventListener('change', function() {
|
|
||||||
if (ldcCheck.checked) {
|
|
||||||
sonstigesCheck.checked = false;
|
|
||||||
sonstigesText.style.display = 'none';
|
|
||||||
sonstigesInput.removeAttribute('required'); // Entferne required, wenn "Sonstiges" abgewählt ist
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
sonstigesCheck.addEventListener('change', function() {
|
|
||||||
checkInput();
|
|
||||||
if (sonstigesCheck.checked) {
|
|
||||||
ldcCheck.checked = false;
|
|
||||||
sonstigesText.style.display = 'block';
|
|
||||||
sonstigesInput.setAttribute('required', 'required'); // Setze required, wenn "Sonstiges" ausgewählt ist
|
|
||||||
} else {
|
|
||||||
sonstigesText.style.display = 'none';
|
|
||||||
sonstigesInput.removeAttribute('required'); // Entferne required, wenn "Sonstiges" abgewählt ist
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// BEARBEITUNGS FORMULAR
|
|
||||||
//
|
|
||||||
|
|
||||||
var edithours = document.getElementById('editStunden')
|
|
||||||
var editMins = document.getElementById('editMinuten')
|
|
||||||
var editldcCheck = document.getElementById('editldcCheck');
|
|
||||||
var editsonstigesCheck = document.getElementById('editsonstigesCheck');
|
|
||||||
var editsonstigesText = document.getElementById('edit-sonstiges-text');
|
|
||||||
var editsonstigesInput = document.getElementById('editsonstigesInput');
|
|
||||||
var EditSaveButton = document.getElementById('editEntrySubmitButton');
|
|
||||||
|
|
||||||
|
|
||||||
// Änderungen überwachen damit die das Formular nicht zu früh abgesendet wird
|
|
||||||
edithours.addEventListener('input', () => {
|
|
||||||
checkEditInput();
|
|
||||||
console.log(this.value)
|
|
||||||
})
|
|
||||||
editMins.addEventListener('input', () => {
|
|
||||||
checkEditInput();
|
|
||||||
console.log(this.value)
|
|
||||||
})
|
|
||||||
editsonstigesInput.addEventListener('input', () => {
|
|
||||||
checkEditInput();
|
|
||||||
console.log(this.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
editldcCheck.addEventListener('change', function() {
|
|
||||||
if (editldcCheck.checked) {
|
|
||||||
editsonstigesCheck.checked = false;
|
|
||||||
editsonstigesText.style.display = 'none';
|
|
||||||
editsonstigesInput.removeAttribute('required'); // Entferne required, wenn "Sonstiges" abgewählt ist
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
editsonstigesCheck.addEventListener('change', function() {
|
|
||||||
checkEditInput();
|
|
||||||
if (editsonstigesCheck.checked) {
|
|
||||||
editldcCheck.checked = false;
|
|
||||||
editsonstigesText.style.display = 'block';
|
|
||||||
editsonstigesInput.setAttribute('required', 'required'); // Setze required, wenn "Sonstiges" ausgewählt ist
|
|
||||||
} else {
|
|
||||||
editsonstigesText.style.display = 'none';
|
|
||||||
editsonstigesInput.removeAttribute('required'); // Entferne required, wenn "Sonstiges" abgewählt ist
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
document.getElementById('editEntrySubmitButton').addEventListener('click', () => {
|
|
||||||
if (!editallowToSend) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var ToEditID = document.getElementById('editEntryID').value
|
|
||||||
// console.log(`ID: ${ToEditID}, Hours: ${editHours.values}, Minutes: ${editMins.values}`)
|
|
||||||
|
|
||||||
var type = 1
|
|
||||||
|
|
||||||
// Abfragen der Checkboxen
|
|
||||||
const ldcCheck = document.getElementById('editldcCheck').checked
|
|
||||||
if (ldcCheck) {
|
|
||||||
type = 2
|
|
||||||
document.getElementById('editldcCheck').checked = false
|
|
||||||
} else if (document.getElementById('editsonstigesCheck').checked) {
|
|
||||||
type = 3;
|
|
||||||
document.getElementById('editsonstigesCheck').checked = false;
|
|
||||||
sonstigesText.style.display = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
updateEntry(parseInt(ToEditID), 'hours', {
|
|
||||||
date: document.getElementById('editDatum').value,
|
|
||||||
duration: ((parseInt(edithours.value) || 0)*60) + (parseInt(editMins.value) || 0),
|
|
||||||
type: type,
|
|
||||||
status: 1,
|
|
||||||
sondertext: document.getElementById('editsonstigesInput').value,
|
|
||||||
partner: document.getElementById('editPartnerInput').value.trim(),
|
|
||||||
}).then(() => {
|
|
||||||
// console.log('Eintrag aktualisiert.');
|
|
||||||
location.reload()
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
document.getElementById('DeleteEntryButton').addEventListener('click', () => {
|
|
||||||
const ToEditID = document.getElementById('editEntryID').value
|
|
||||||
|
|
||||||
deleteEntry(parseInt(ToEditID)).then(() => {
|
|
||||||
console.log(`Löschen von Eintrag: ${ToEditID}`);
|
|
||||||
location.reload()
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// MONATSANSICHT Anpassen
|
|
||||||
//
|
|
||||||
|
|
||||||
const monthEntrys = document.querySelectorAll('.monthEntrys');
|
|
||||||
|
|
||||||
// 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', () =>{
|
|
||||||
if (!document.getElementById('dashbord_month_area').classList.contains('ActiveMonth')) {
|
|
||||||
document.getElementById('dashbord_month_area').classList.replace('closeMonthArea', 'openMonthArea')
|
|
||||||
document.getElementById('dashbord_month_area').classList.add(['openMonthArea'])
|
|
||||||
document.getElementById('dashbord_month_area').classList.add(['ActiveMonth'])
|
|
||||||
// ActivitysTable ist jetzt flex:1 1 auto (siehe custom.css) und macht der wachsenden
|
|
||||||
// Monatskarte automatisch Platz - kein manuelles shrinkActivitys/growActivitys mehr nötig,
|
|
||||||
// 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-3')
|
|
||||||
// document.getElementById('dashbord_year_area').classList.add('fade-out')
|
|
||||||
// Für jedes ausgewählte Element die neue Klasse hinzufügen
|
|
||||||
setTimeout(function() {
|
|
||||||
monthEntrys.forEach(element => {
|
|
||||||
if (element.classList.contains('fade-out')) {
|
|
||||||
element.classList.replace('fade-out', 'fade-in');
|
|
||||||
} else {
|
|
||||||
element.classList.add('fade-in');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
document.getElementById('MonthNameOfActual').innerHTML = "Aktuell:"
|
|
||||||
}, 300);
|
|
||||||
} else {
|
|
||||||
document.getElementById('dashbord_month_area').classList.remove('ActiveMonth')
|
|
||||||
document.getElementById('dashbord_month_area').classList.replace('openMonthArea', 'closeMonthArea')
|
|
||||||
document.getElementById('dashbord_month_area').classList.add('mt-3')
|
|
||||||
monthEntrys.forEach(element => {
|
|
||||||
element.classList.replace('fade-in', 'fade-out');
|
|
||||||
});
|
|
||||||
document.getElementById('MonthNameOfActual').innerHTML = "Monat:"
|
|
||||||
cursorMonth = new Date().getMonth();
|
|
||||||
cursorYear = new Date().getFullYear();
|
|
||||||
getActualDataAndFillView(cursorMonth, cursorYear)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
document.getElementById('btn-month-before').addEventListener('click', () =>{
|
|
||||||
if (cursorMonth === 0) {
|
|
||||||
// Januar -> Dezember des Vorjahres
|
|
||||||
cursorMonth = 11;
|
|
||||||
cursorYear -= 1;
|
|
||||||
} else {
|
|
||||||
cursorMonth -= 1;
|
|
||||||
}
|
|
||||||
getActualDataAndFillView(cursorMonth, cursorYear)
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('btn-month-next').addEventListener('click', () =>{
|
|
||||||
if (cursorMonth === 11) {
|
|
||||||
// Dezember -> Januar des Folgejahres
|
|
||||||
cursorMonth = 0;
|
|
||||||
cursorYear += 1;
|
|
||||||
} else {
|
|
||||||
cursorMonth += 1;
|
|
||||||
}
|
|
||||||
getActualDataAndFillView(cursorMonth, cursorYear)
|
|
||||||
})
|
|
||||||
|
|
||||||
function setNewCalsOfMonth(TheMonth) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// FUNKTIONEN LIBARY
|
|
||||||
//
|
|
||||||
|
|
||||||
function checkInput() {
|
|
||||||
// Eingabe feld für Beschreibung leeren wenn sonstiges abgewählt wird
|
|
||||||
if (!sonstigesCheck.checked) {
|
|
||||||
sonstigesInput.value = null;
|
|
||||||
}
|
|
||||||
// Debug ausgabe er Werte
|
|
||||||
// console.log(`Check: ${sonstigesCheck.checked} - Input: ${sonstigesInput.value} - Stunden: ${hours.value} - Min: ${mins.value}`)
|
|
||||||
|
|
||||||
// Berechtigungen durch gehen damit Button verfügbar und Form abgesendet werden kann
|
|
||||||
if ((sonstigesCheck.checked && sonstigesInput.value !== "") || !(sonstigesCheck.checked)) {
|
|
||||||
// Debug Ausgabe für Bedingungsstufen
|
|
||||||
// console.log("Erste Bedingung: TRUE")
|
|
||||||
if (mins.value) { // Stunden sind optional, Minuten bleiben Pflicht
|
|
||||||
// Debug Ausgabe für Bedingungsstufen
|
|
||||||
// console.log("Zweite Bedingung: TRUE")
|
|
||||||
if (!allowToSend) {
|
|
||||||
// Debug Ausgabe für Bedingungsstufen
|
|
||||||
// console.log("Dritte Bedingung: TRUE")
|
|
||||||
allowToSend = true;
|
|
||||||
NewEntryButton.classList.remove('disabled');
|
|
||||||
NewEntryButton.classList.replace('btn-light', 'btn-primary');
|
|
||||||
NewEntryButton.disabled = false;
|
|
||||||
}
|
|
||||||
} else if (allowToSend) {
|
|
||||||
allowToSend = false;
|
|
||||||
NewEntryButton.classList.add('disabled');
|
|
||||||
NewEntryButton.classList.replace('btn-primary', 'btn-light');
|
|
||||||
NewEntryButton.disabled = true;
|
|
||||||
}
|
|
||||||
} else if (allowToSend) {
|
|
||||||
allowToSend = false;
|
|
||||||
NewEntryButton.classList.add('disabled');
|
|
||||||
NewEntryButton.classList.replace('btn-primary', 'btn-light');
|
|
||||||
NewEntryButton.disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var editallowToSend = true;
|
|
||||||
function checkEditInput() {
|
|
||||||
var edithours = document.getElementById('editStunden')
|
|
||||||
var editMins = document.getElementById('editMinuten')
|
|
||||||
var editsonstigesCheck = document.getElementById('editsonstigesCheck');
|
|
||||||
var editsonstigesText = document.getElementById('edit-sonstiges-text');
|
|
||||||
var editsonstigesInput = document.getElementById('editsonstigesInput');
|
|
||||||
var EditSaveButton = document.getElementById('editEntrySubmitButton');
|
|
||||||
|
|
||||||
// Eingabe feld für Beschreibung leeren wenn sonstiges abgewählt wird
|
|
||||||
if (!editsonstigesCheck.checked) {
|
|
||||||
editsonstigesInput.value = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Berechtigungen durch gehen damit Button verfügbar und Form abgesendet werden kann
|
|
||||||
if ((editsonstigesCheck.checked && editsonstigesInput.value !== "") || !(editsonstigesCheck.checked)) {
|
|
||||||
// Debug Ausgabe für Bedingungsstufen
|
|
||||||
// console.log("Erste Bedingung: TRUE")
|
|
||||||
if (editMins.value) { // Stunden sind optional, Minuten bleiben Pflicht
|
|
||||||
// Debug Ausgabe für Bedingungsstufen
|
|
||||||
// console.log("Zweite Bedingung: TRUE")
|
|
||||||
if (!editallowToSend) {
|
|
||||||
// Debug Ausgabe für Bedingungsstufen
|
|
||||||
// console.log("Dritte Bedingung: TRUE")
|
|
||||||
editallowToSend = true;
|
|
||||||
EditSaveButton.classList.remove('disabled');
|
|
||||||
EditSaveButton.classList.replace('btn-light', 'btn-primary');
|
|
||||||
EditSaveButton.disabled = false;
|
|
||||||
}
|
|
||||||
} else if (editallowToSend) {
|
|
||||||
editallowToSend = false;
|
|
||||||
EditSaveButton.classList.add('disabled');
|
|
||||||
EditSaveButton.classList.replace('btn-primary', 'btn-light');
|
|
||||||
EditSaveButton.disabled = true;
|
|
||||||
}
|
|
||||||
} else if (editallowToSend) {
|
|
||||||
editallowToSend = false;
|
|
||||||
EditSaveButton.classList.add('disabled');
|
|
||||||
EditSaveButton.classList.replace('btn-primary', 'btn-light');
|
|
||||||
EditSaveButton.disabled = true;
|
|
||||||
}
|
|
||||||
// Debug ausgabe er Werte
|
|
||||||
console.log(`Status: ${editallowToSend} - Check: ${editsonstigesCheck.checked} - Input: ${editsonstigesInput.value} - Stunden: ${edithours.value} - Min: ${editMins.value}`)
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
def parse_user_agent(user_agent):
|
|
||||||
"""Sehr einfache, dependency-freie Grobzuordnung von Plattform/Browser aus dem
|
|
||||||
User-Agent-String - reicht für die Dashboard-Statistik, muss nicht exakt sein."""
|
|
||||||
ua = (user_agent or "").lower()
|
|
||||||
|
|
||||||
if "iphone" in ua or "ipad" in ua or "ipod" in ua:
|
|
||||||
platform = "iOS"
|
|
||||||
elif "android" in ua:
|
|
||||||
platform = "Android"
|
|
||||||
elif "windows" in ua:
|
|
||||||
platform = "Windows"
|
|
||||||
elif "macintosh" in ua or "mac os x" in ua:
|
|
||||||
platform = "macOS"
|
|
||||||
elif "linux" in ua:
|
|
||||||
platform = "Linux"
|
|
||||||
else:
|
|
||||||
platform = "Unbekannt"
|
|
||||||
|
|
||||||
if "edg/" in ua or "edga" in ua or "edgios" in ua:
|
|
||||||
browser = "Edge"
|
|
||||||
elif "opr/" in ua or "opera" in ua:
|
|
||||||
browser = "Opera"
|
|
||||||
elif "firefox" in ua or "fxios" in ua:
|
|
||||||
browser = "Firefox"
|
|
||||||
elif "crios" in ua or "chrome" in ua:
|
|
||||||
browser = "Chrome"
|
|
||||||
elif "safari" in ua:
|
|
||||||
browser = "Safari"
|
|
||||||
else:
|
|
||||||
browser = "Unbekannt"
|
|
||||||
|
|
||||||
return platform, browser
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
from django.conf import settings
|
|
||||||
|
|
||||||
|
|
||||||
def static_version(request):
|
|
||||||
"""Stellt STATIC_VERSION allen Templates zur Verfügung, um CSS/JS-URLs mit
|
|
||||||
?v=<version> zu versehen (Cache-Busting bei Bestandsnutzern, siehe settings.py)."""
|
|
||||||
return {'STATIC_VERSION': getattr(settings, 'STATIC_VERSION', '')}
|
|
||||||
Loading…
Reference in new issue