redesign for mulituser

change validation concept (client and server)
using entities
This commit is contained in:
Markus
2026-10-06 08:55:35 +02:00
parent 14e050e4ba
commit 995e2ec111
41 changed files with 2402 additions and 1223 deletions

View File

@@ -918,7 +918,9 @@
z-index: 10;
overflow-y: auto;
bottom: 0;
background-color: var(--bs-body-bg);
transition: left .5s ease-out
}
.sidebar-wrapper .sidebar-header {

View File

@@ -1,6 +1,10 @@
.dt-amount, .dt-subamount{
text-align:right;
}
.invalid-feedback{
text-align:right;
}
.dataTables_info{
float:left;
padding-top:0px !important;
@@ -10,6 +14,19 @@
float:left;
}
.datatable-sorter {
color: inherit;
background-color: inherit;
border-color: inherit;
border: 0;
padding: 0;
font-weight:700;
}
.datatable-icon {
padding-left:0 !important;
padding-right:0 !important;
}
.toolbar, .syncbutton{
float:left;
padding-left:10px;

View File

@@ -1,67 +1,71 @@
function newCat(){
$('#editor').removeClass('d-none');
$("#id").val(0);
tree = document.getElementById('tree');
editor = document.getElementById("editor");
var elementTop = $('#editor').offset().top;
var elementBottom = elementTop + $(this).outerHeight();
var viewportTop = $(window).scrollTop();
var viewportBottom = viewportTop + $(window).height();
if (!(elementBottom > viewportTop && elementTop < viewportBottom))
editor.scrollIntoView( {behavior: "smooth" });
function moveEditor(){
treepos = 90 - document.getElementById("tree").getBoundingClientRect().top;
editor.style.position = 'relative';
editor.style.top = treepos+'px';
}
function scrollToEditor(){
let editor = document.getElementById("editor");
editor.scrollIntoView( {behavior: "smooth" });
}
$(function () {
$('.tree li:has(ul)').addClass('parent_li').find(' > span');
$('.tree li.parent_li > span').on('click', function (e) {
var children = $(this).parent('li.parent_li').find(' > ul > li');
if (children.is(":visible")) {
children.hide('fast');
// $(this).find(' > i').addClass('icon-plus-sign').removeClass('icon-minus-sign');
} else {
children.show('fast');
// $(this).find(' > i').addClass('icon-minus-sign').removeClass('icon-plus-sign');
}
e.stopPropagation();
});
$("span").on('click', function(e){
$('#editor').removeClass('d-none');
bookable = ($(this).attr('data-bookable') == "f")?false:true;
lkz = ($(this).attr('data-lkz') == 0)?false:true;
type = $(this).attr('data-type');
pid = $(this).attr('data-pid');
id = $(this).attr('data-id');
description = $(this).attr('data-description');
typeAccount = (type === "account") ? true : false;
typeInput = (type === "input") ? true : false;
typeOutput = (type === "output") ? true : false;
$('#bookable').prop('checked', bookable);
$('#typeInput').prop('checked', typeInput);
$('#typeOutput').prop('checked', typeOutput);
$('#typeAccount').prop('checked', typeAccount);
$('#lkz').prop('checked', lkz);
$("#parent").val(pid).change();
$("#id").val(id);
$("#description").val(description).change();
tree = document.getElementById('tree');
editor = document.getElementById("editor");
var elementTop = $('#editor').offset().top;
var elementBottom = elementTop + $(this).outerHeight();
var viewportTop = $(window).scrollTop();
var viewportBottom = viewportTop + $(window).height();
if (!(elementBottom > viewportTop && elementTop < viewportBottom))
editor.scrollIntoView( {behavior: "smooth" });
//$('#parent').prop('selected', pid);
function newCat(){
document.getElementById("editor").classList.remove("d-none");
document.getElementById("id").value = 0;
document.getElementById("bookable").checked = true;
document.getElementById("account").checked = false;
document.getElementById("monitor").checked = false;
document.getElementById("deleted_at").checked = false;
document.getElementById("parent").value = 0;
document.getElementById("description").value = "";
// scrollEditor();
}
// title: "Edit Account",
// placement: 'bottom',
// html: true,
// content: $('[data-name="popover-content"]')
document.addEventListener("DOMContentLoaded", function(event) {
editor = document.getElementById("editor");
document.querySelectorAll('.tree li:has(ul)').forEach((single) => {
single.classList.add("parent_li");
single.getElementsByTagName("i")[0].classList.add("fa-square-minus");
});
document.querySelectorAll(".tree span").forEach((spa) => {
spa.addEventListener("dblclick", (event) => {
const viewportWidth = document.documentElement.clientWidth;
if (viewportWidth < 768)
scrollToEditor();
else
moveEditor();
editor.classList.remove("d-none");
document.getElementById("bookable").checked = event.target.getAttribute("data-bookable")=="true";
document.getElementById("account").checked = event.target.getAttribute("data-account")=="true";
document.getElementById("monitor").checked = event.target.getAttribute("data-monitor")=="true";
document.getElementById("deleted_at").checked = event.target.getAttribute("data-deleted")!== "";
document.getElementById("id").value = event.target.getAttribute("data-id");
document.getElementById("parent").value = event.target.getAttribute("data-pid");
document.getElementById("description").value = event.target.getAttribute("data-description");
// scrollEditor();
});
});
document.querySelectorAll('.tree li.parent_li > span, .tree li.parent_li > i').forEach((parent) => {
parent.addEventListener("click",(event) => {
let single = event.target.parentElement.querySelector('ul,li');
let visible = single.classList.toggle("d-none");
if (visible) {
event.target.parentElement.querySelector("i").classList.add("fa-square-plus");
event.target.parentElement.querySelector("i").classList.remove("fa-square-minus");
} else {
event.target.parentElement.querySelector("i").classList.add("fa-square-minus");
event.target.parentElement.querySelector("i").classList.remove("fa-square-plus");
}
});
});
document.getElementById("viewdeleted").addEventListener("click",(event) => {
document.querySelectorAll(".tree span").forEach((spa) => {
if (event.currentTarget.checked && spa.getAttribute("data-deleted")!== "")
spa.parentElement.classList.remove("d-none");
else if ((!event.currentTarget.checked) && spa.getAttribute("data-deleted")!== "")
spa.parentElement.classList.add("d-none");
});
});
});

View File

@@ -1,57 +0,0 @@
var datatable;
var colomnspez = columns;
function createSearchData(data, type, row){
let details = "";
data.forEach(function(item){
details += item.comment+' '+item.description+' ';
details += new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(item.subamount);
});
return details;
}
colomnspez.splice(3, 0, { title: "Quelle",orderable:false, data: "source",className:"dt-source" });
colomnspez.splice(6, 0, { title: "Details",orderable:false, visible:false, searchable:true, data: "details",className:"",render: createSearchData});
$(document).ready(function(){
datatable = $('#bookings').DataTable({
paging: false,
searching:true,
scrollX:false,
info:false,
order: [[ 1, 'desc' ],[ 0, 'desc' ]],
"processing": true,
ajax: {
type : 'POST',
url : '/Ajax/getTabelData',
data : function(d){
d.datum_start = $('#datepickers').val();
d.datum_ende = $('#datepickere').val();
d.source = $('#source').val();
},
dataSrc:''},
layout: {
topStart: {
buttons: [
{text:'Neue Rechnung',className:'btn-sm',action: function ( e, dt, node, config ) {
location.href = '/newBill/';
}},
{text:'Neuer Transfer',className:'btn-sm mx-2',action: function ( e, dt, node, config ) {
location.href = '/newTransfer/';
}},
]
},
topEnd: 'search'
},
// dom: '<"toolbar">frt',
"createdRow": function ( row, data, index ) {
if(data.validate == "t"){
$(row).addClass('text-bg-warning');
}
},
columns: colomnspez,
});
// $("div.toolbar").html('<a class="btn-sm btn-secondary mx-2" href="/newBill" role="button">Neue Rechnung</a><a class="btn-sm btn-secondary" href="/newTransfer" role="button">Neuer Transfer</a>');
$('#bookings tbody').on('click', 'td.dt-receiver', function () {collapseDetails($(this), datatable);} );
$('#bookings tbody').on('click', 'td.dt-datum', function () {location.href = '/editBill/'+getId($(this),datatable);});
$('#bookings tbody').on('click', 'table.tabdet', function () {location.href = '/editBill/'+$(this).attr('data-bs-id');});
});

View File

@@ -1,35 +1,146 @@
$(function () {
$('.parent').change(function () {
var $subs = $(this).parent().parent().children(".sub").children();
$subs.children().remove().end();
var $output = '';
$liste = subsdata[$(this).val()];
$sort = Object.entries($liste).sort((a, b) => (a[1] > b[1]) ? 1 : (b[1] > a[1]) ? -1 : 0);
$.each($sort, function (key, value) {
$output += '<option value="' + value[0] + '">' + value[1] + '</option>';
});
$subs.append($output);
document.addEventListener("DOMContentLoaded", function(event) {
document.myModal = document.getElementById('mymodal');
document.myModalDelete = document.getElementById('mymodalDelete');
document.myModalDelete.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget;
var id = button.getAttribute('data-bs-id');
var tab = button.getAttribute('data-bs-table');
document.myModalDelete.setAttribute('data-bs-id',id);
document.myModalDelete.setAttribute('data-bs-table',tab);
});
document.myModal.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget;
var id = button.getAttribute('data-bs-id');
var tab = button.getAttribute('data-bs-table');
document.myModal.setAttribute('data-bs-id',id);
document.myModal.setAttribute('data-bs-table',tab);
});
$('#multi').change(function () {
if ($(this).is(":checked")) {
$('.single').addClass('d-none');
$('.multi').removeClass('d-none');
return;
}
$('.single').removeClass('d-none');
$('.multi').addClass('d-none');
//'unchecked' event code
}).change();
$('.dt-amount, .dt-subamount').change(function () {
var temp = convertInput($(this).val());
$(this).val(convertOutput(temp));
if ($('#multi').is(":checked")) {
recalcOpenAmount();
}
}).change();
document.getElementById('modal_delete').addEventListener('click', deleteEntry );
var event = new Event('change');
switchMulti();
// dropdown elemente anpassen wenn parent sich ändert
document.querySelectorAll(".parent").forEach((papa) => {
papa.addEventListener("change", hdlDropDownChange);
});
document.querySelectorAll(".dt-amount.input,.dt-amount.output , .dt-subamount").forEach((amount) => {
amount.addEventListener("change", hdlAmountChange);
amount.dispatchEvent(event);
});
document.querySelectorAll(".dt-amount.input,.dt-amount.output,.dt-subamount, .parent").forEach((amount) => {
amount.addEventListener("focus", hdlValidityStateLine);
});
const form = document.getElementById('newbill');
form.addEventListener('formdata', function(event) {
const formData = event.formData;
formData.set('validate', formData.has('validate') ? '1' : '0');
// console.log(formData);
});
});
function loadPage(ev){
let url = ev.relatedTarget.getAttribute('url');
window.location.href="url";
}
function switchMulti(){
//const multi = document.getElementById("multi");
if (document.getElementById("linecont").childElementCount>1) {
document.getElementById("multiadd").text = "+Zeile";
const singles = document.querySelectorAll(".single").forEach((single) => {
single.classList.add("d-none");
});
const multis = document.querySelectorAll(".multi").forEach((multi) => {
multi.classList.remove("d-none");
});
// addLine();
} else {
document.getElementById("multiadd").text = "Multi";
const singles = document.querySelectorAll(".single").forEach((single) => {
single.classList.remove("d-none");
});
const multis = document.querySelectorAll(".multi").forEach((ele) => {
ele.classList.add("d-none");
});
}
}
function recalcRow(einnahme, ausgabe){
let value = einnahme.value - ausgabe.value;
if (value < 0) {
ausgabe.value = convertOutput(value *(-1));
einnahme.value = '';
} else {
einnahme.value = convertOutput(value);
ausgabe.value = '';
}
}
function hdlAmountChange(event) {
var temp = convertInput(event.target.value);
event.target.value = convertOutput(temp);
let zeile = event.target.parentElement.parentElement;
var einnahme = zeile.querySelector(".input");
var ausgabe = zeile.querySelector(".output");
if (event.target.classList.contains("input")) {
if ( ausgabe.value !== '')
recalcRow(einnahme,ausgabe);
}else {
if ( einnahme.value !== '')
recalcRow(einnahme, ausgabe);
}
calcAmount();
if (document.getElementById("linecont").childElementCount>1) {
recalcOpenAmount();
}
}
function hdlDropDownChange(event) {
var $sub = event.target.parentElement.parentElement.querySelector(".sub");
while ($sub.options.length) {
$sub.remove(0);
}
var output = '';
var liste = subsdata[(event.target.value=="")?0:event.target.value];
var sort = Object.entries(liste).sort((a, b) => (a[1] > b[1]) ? 1 : (b[1] > a[1]) ? -1 : 0);
sort.forEach((value) => {
output += '<option value="' + value[0] + '">' + value[1] + '</option>';
});
$sub.innerHTML = output;
}
function hdlValidityState(ev){
form = document.getElementById("newbill");
this.classList.remove("is-invalid");
this.setCustomValidity("");
form.classList.remove('was-validated');
}
function hdlValidityStateLine(ev){
let form = document.getElementById("newbill");
if (form.classList.contains('was-validated')) {
//ev.target.parentNode.parentNode
//document.getElementById("linecont").
form.querySelectorAll(".dt-amount, .dt-subamount, .parent, .sub").forEach((amount) => {
amount.setCustomValidity("");
amount.classList.remove("is-invalid");
amount.classList.remove("is-valid");
});
form.classList.remove('was-validated');
}
}
function logData(event) {
var data = document.getElementById("billfile");
console.log(data.value);
@@ -37,12 +148,21 @@ function logData(event) {
}
function addLine() {
$('#linecont > div').each(function () {
if ($(this).hasClass("d-none")) {
$(this).removeClass("d-none");
return false;
}
//let ele =document.querySelector("#linecont > div:last-child");
var clonedDiv = document.getElementById("template").cloneNode(true);
clonedDiv.removeAttribute("id");
clonedDiv.classList.remove("d-none");
clonedDiv.querySelector(".parent").addEventListener("change", hdlDropDownChange);
clonedDiv.querySelectorAll(".dt-subamount").forEach((amount) => {
amount.addEventListener("change", hdlAmountChange);
});
clonedDiv.querySelectorAll(".dt-subamount, .parent").forEach((amount) => {
amount.addEventListener("focus", hdlValidityStateLine);
});
document.getElementById("linecont").appendChild(clonedDiv);
if (document.getElementById("linecont").childElementCount==2){
switchMulti();
}
}
function removeBillFile(e) {
@@ -79,23 +199,97 @@ function convertOutput(number) {
return "";
}
function recalcOpenAmount() {
var summe = 0.0;
$('.dt-subamount').each(function () {
b = $(this).val();
b = convertInput(b);
function calcAmount() {
//let amount = convertInput(document.getElementsByName("amount")[0].value);
let amount = 0.0;
document.querySelectorAll(".dt-subamount").forEach((subamount) => {
var b = convertInput(subamount.value);
if (typeof b !== 'undefined') {
b = $(this).hasClass("text-danger") ? b * (-1) : b;
summe = summe + b;
b = subamount.classList.contains("output") ? b * (-1) : b;
amount = amount + b;
}
// summe = summe + convertInput($(this).val());
});
document.getElementsByName("amount")[0].value = convertOutput(amount);
$('#openamount').val(Math.round(($('#total_in').val() - $('#total_out').val() - summe) * 100) / 100);
}
// $('form').submit(function () {
// alert("disable elements");
// $( ".d-none" ).prop( "disabled", true );
// return true;
// });
function recalcOpenAmount() {
form = document.getElementById('newbill');
let summe = convertInput(document.getElementsByName("amount")[0].value);
console.log("Re calculating open amount");
var total_in = convertInput(document.getElementById("total_in").value || "0.0");
var total_out = convertInput(document.getElementById("total_out").value || "0.0");
let val = convertOutput(Math.round((total_in - total_out - summe) * 100) / 100);
if (parseFloat(val) !== 0.0){
setValState(form.openamount,"Muss 0 sein");
} else {
setValState(form.openamount,"Muss 0 sein",true);
}
document.getElementById("openamount").value = val;
}
function setValState(ele, message,valid=false){
if (valid){
ele.classList.add("is-valid");
ele.classList.remove("is-invalid");
ele.setCustomValidity("");
} else {
ele.classList.add("is-invalid");
ele.classList.remove("is-valid");
ele.setCustomValidity(message);
}
}
function checkForm(e,form) {
const subinputs = form.elements;
//for new transfer
if (form.receiver.value =='' && form.transfer.value)
form.receiver.value = subinputs['parent_id[]'].selectedOptions[0].text+"-"+subinputs['account_id[]'].selectedOptions[0].text;
if (!form.total_in.parentElement.parentElement.classList.contains("d-none")) {
//Gesamtbetrag fehlt
if ((form.total_in.value == "" ) && (form.total_out.value == "")) {
if (parseFloat(form.amount.value) > 0.0){
setValState(form.total_in, "Notwendig");
} else {
setValState(form.total_out, "Notwendig");
}
}
//Restbetrag
if (parseFloat(form.openamount.value) !== 0.0){
setValState(form.openamount, "Offener Betrag!");
form.openamount.readOnly = false;
}else{
setValState(form.openamount, "Offener Betrag!",true);
}
subinputs['account_id[]'].forEach((line,index) => {
//wenn Kategorie gewählt muss Betrag da sein
if (line.value > 0){
if (!((parseFloat(subinputs['output[]'][index].value) > 0.0) || (parseFloat(subinputs['input[]'][index].value) > 0.0))){
setValState(subinputs['output[]'][index],"Notwendig");
setValState(subinputs['input[]'][index],"Notwendig");
} else {
setValState(subinputs['output[]'][index],"Notwendig",true);
setValState(subinputs['input[]'][index],"Notwendig",true);
}
}
else if ((subinputs['output[]'][index].value !=="") || (subinputs['input[]'][index].value !=="")){
setValState(line,"Notwendig");
setValState(subinputs['parent_id[]'][index],"Notwendig");
}
else {
setValState(line,"Notwendig",true);
setValState(subinputs['parent_id[]'][index],"Notwendig",true);
}
});
}
if (!form.checkValidity()) {
e.preventDefault();
e.stopPropagation();
form.openamount.readOnly = true;
}
form.classList.add('was-validated');
}

View File

@@ -1,26 +1,66 @@
function syncScheduled(){
$('#mySnycModal').modal('show');
$('#mySnycModal').find('.modal-title').html("Synchronisierte Einträge!");
$.ajax({
type: "GET",
url: "/syncScheduled/",
data: {}, // serializes the form's elements.
success: function(data){
const myModale = document.querySelector('#mySnycModal');
var modalText = myModale.querySelector('.modal-body');
var modalFenster = myModale.querySelector('.modal-dialog');
modalText.innerHTML = data;
$('#todos').DataTable().ajax.reload();
},
error: function(data){
const myModale = document.querySelector('#mySnycModal');
var modalText = myModale.querySelector('.modal-body');
var modalFenster = myModale.querySelector('.modal-dialog');
modalFenster.classList.add("alert");
modalFenster.classList.add("alert-danger");
modalText.textContent = 'Fehler bei der Ausführung!';
$('#todos').DataTable().ajax.reload();
function syncScheduled(ele){
var myModal = document.getElementById('mySnycModal');
var modalTitle = myModal.querySelector('.modal-title');
let modalBody = myModal.querySelector('.modal-body');
modalTitle.textContent = 'Synchronisierte Einträge!';
modalBody.textContent = 'Please Wait!';
fetch("/syncScheduled", { method: "GET",headers: {"X-Requested-With": "XMLHttpRequest"},})
.then(response => response.text())
.then(data => {
const myModale = document.querySelector('#mySnycModal');
var modalBody = myModale.querySelector('.modal-body');
if (data === "") {
modalBody.innerHTML = "Nix Neues Synchronisiert!";
}
});
// location.href = '/syncScheduled/';
else
modalBody.innerHTML = data;
if (typeof loadToDosData === "function")
loadToDosData();
})
.catch(
error => {
const myModale = document.querySelector('#mySnycModal');
var modalBody = myModale.querySelector('.modal-body');
modalBody.innerHTML = "Fehler bei der Ausführung! " + error;
}
);
}
function deleteEntry(event) {
let myModalDelete = document.getElementById('mymodalDelete');
let id = myModalDelete.getAttribute('data-bs-id');
let table = myModalDelete.getAttribute('data-bs-table');
let formData = new FormData();
formData.set('id',id);
if (table == "scheduled")
cmnd = "/deleteScheduled";
else
cmnd = "/deleteBill";
fetch(cmnd, { method: "POST",headers: {"X-Requested-With": "XMLHttpRequest"}, body: formData})
.then(response => {
let myModal = document.getElementById('mymodal');
let body = myModal.querySelector('.modal-body');
if (!response.ok){
body.innerHTML = response.statusText;
}
else{
myModal.addEventListener('hidden.bs.modal', event => {
let url = event.target.getAttribute('data-bs-url');
window.location.href= url;
})
//document.getElementById('modal_ok').addEventListener('click', loadPage );
response.json().then(json => {
console.log(json);
myModal.setAttribute('data-bs-url',json.url);
body.innerHTML = "Erfolgreich gelöscht " + json.ID;
})
}
})
.catch(
error => {
let body = myModal.querySelector('.modal-body');
body.innerHTML = "Fehler bei der Ausführung! " + error;
}
);
}

View File

@@ -1,32 +0,0 @@
var datatable;
var columnspez = columns;
columnspez.splice(3, 0, { title: "Quelle",orderable:false, data: "source",className:"dt-source" });
$(document).ready(function(){
datatable = $('#scheduled').DataTable({
paging: false,
searching:true,
scrollX:false,
info:false,
order: [[ 1, 'asc' ]],
ajax: {url: '/Ajax/getScheduledData',dataSrc:''},
layout: {
topStart: {
buttons: [
{text:'Neue Rechnung',className:'btn-sm',action: function ( e, dt, node, config ) {
location.href = '/newScheduled';
}},
{text:'Neuer Transfer',className:'btn-sm mx-2',action: function ( e, dt, node, config ) {
location.href = '/newScheduledTransfer';
}},
]
},
topEnd: 'search'
},
columns: columnspez
});
$('#scheduled tbody').on('click', 'td.dt-receiver', function () {collapseDetails($(this), datatable);} );
$('#scheduled tbody').on('click', 'td.dt-datum', function () {location.href = '/editScheduled/'+getId($(this),datatable);});
$('#scheduled tbody').on('click', 'table.tabdet', function () {location.href = '/editScheduled/'+$(this).attr('data-bs-id');});
});

View File

@@ -1,16 +1,59 @@
var accounts;
$(document).ready(function(){
accounts = $('#accounts').DataTable({
var accountsdata;
function loadAccountsData(){
document.accounts.setMessage("Loading Data");
let status;
fetch("/getAccountsBalance", { method: "GET",headers: {"X-Requested-With": "XMLHttpRequest"},})
.then(response => {
status = response.statusText;
if (!response.ok) {
throw "HTTP error: " + response.status + "; " + status;
} else
return response.json();
})
.then(data => {
if (document.accounts.hasRows){
document.accounts.data.data.splice(0,document.accounts.data.data.length);
document.accounts.hasRows = false;
}
document.accounts.insert({data:data.map(item => [item.description,item.amount])});
document.accounts.update(true);
})
.catch(err => {
document.accounts.setMessage(err);
});
}
function createDtAccounts(){
document.accounts = new simpleDatatables.DataTable("#accounts", {
searchable: false,
paging: false,
searching:true,
scrollX:false,
info:false,
ajax: { url: '/Ajax/getAccountsBalance', dataSrc:''},
layout: { topEnd: 'search' },
// dom: '<"toolbar">frtip',
data: {
headings: ["Konto","Betrag"],
data: accountsdata,
},
classes: {
active: "active",
disabled: "disabled",
table: "table table-striped table-sm",
},
columns: [
{ title: "Konto",orderable:false, data: "description",className:"dt-receiver" },
colBetrag
]
{
select:0,
type: 'string',
cellClass:"dt-receiver",
},{
select:1,
type: 'number',
headerClass: "dt-amount",
cellClass:"dt-amount",
render: renderAmount
}
]
});
});
loadAccountsData();
}
document.addEventListener("DOMContentLoaded", function(event) {
createDtAccounts();
});

111
public/js/tab_activities.js Normal file
View File

@@ -0,0 +1,111 @@
var activitydata;
var colomnspez = columns;
function loadActivityData(){
document.activities.setMessage("Loading Data");
const form = document.querySelector("#getData");
let formData = new FormData(form);
// formData.append('start', document.getElementById("datum_start").value);
// formData.append('end', document.getElementById("datum_ende").value);
// formData.append('source', document.getElementById("source").value);
fetch("/getActivitiesData", { method: "POST",headers: {"X-Requested-With": "XMLHttpRequest"}, body: formData })
.then(response => {
let status = response.statusText;
if (!response.ok) {
throw "HTTP error: " + response.status + "; " + status;
} else
return response.json();
})
.then(data => {
if (document.activities.hasRows){
document.activities.data.data.splice(0,document.activities.data.data.length);
document.activities.hasRows = false;
}
//document.activities.insert({data:data});
document.activities.insert({data:data.map(item => [item.id,item.datum,item.receiver,item.source,item.amount,item.validate])});
document.activities.update(true);
})
.catch(err => {
document.activities.setMessage(err);
});
}
function createDtActivities(){
document.activities = new simpleDatatables.DataTable("#activities", {
searchable: true,
paging: false,
classes: {
active: "active",
disabled: "disabled",
table: "table table-striped table-sm",
},
data: {
headings: ["","Datum","Empfänger",,"Quelle","Betrag","draft"],
data: activitydata,
},
rowRender: (row, tr, _index) => {
//tr.childNodes[1].childNodes[0].attributes.href = `editBill/${row.cells[0].data}`;
tr.childNodes[1].attributes.onclick = `location.href='editBill/${row.cells[0].data}'`;
if(row.cells[5].data == true){
tr.attributes.class = 'text-bg-warning';
}
// $(row).addClass('text-bg-warning');
// tr.childNodes[2].attributes.onclick = `collapseDetails(this, ${_index})`;
},
columns: [
{
select:0,
render: (data, _cell, _dataIndex, _cellIndex) => { return `<a data-bs-toggle="modal" role="button" data-bs-id="${data}" data-bs-target="#mymodalDelete" ><i class="fa-solid fa-trash"></a>` },
cellClass: "datatable-icon",
type: "number",
},{
select:1,
type: 'date',
format: 'dd.mm.yyyy',
cellClass:"dt-datum",
sortable: true,
sort: "desc",
},{
select:2,
type: 'string',
cellClass:"dt-receiver",
// render: (data, _cell, _dataIndex, _cellIndex) => { return `<a onclick="collapseDetails(this,document.bookings)">${data}</a>` },
},{
select:3,
type: 'string',
cellClass:"dt-source",
// render: (data, _cell, _dataIndex, _cellIndex) => { return `<a onclick="collapseDetails(this,document.bookings)">${data}</a>` },
},{
select:4,
type: 'number',
headerClass: "dt-amount",
cellClass:"dt-amount",
render: renderAmount
},{
select:5,
type: 'boolean',
hidden:true,
}
],
template: (options, dom) => `<div class='${options.classes.top}'>
<div class='float-start'>
<a class="btn btn-sm btn-secondary" href="newBill">Neue Rechnung</a>
<a class="btn btn-sm btn-secondary" href="newTransfer">Neuer Transfer</a>
</div>
<div class='${options.classes.search} float-end'>
<input class='${options.classes.input}' placeholder='Search' type='search' title='${options.labels.searchTitle}'${dom.id ? ` aria-controls="${dom.id}"` : ""}>
</div>
</div>
<div class='${options.classes.container}'${options.scrollY.length ? ` style='height: ${options.scrollY}; overflow-Y: auto;'` : ""}></div>
<div class='${options.classes.bottom}'>
</div>`
});
loadActivityData();
}
document.addEventListener("DOMContentLoaded", function(event) {
createDtActivities();
});

88
public/js/tab_overview.js Normal file
View File

@@ -0,0 +1,88 @@
var bookingdata;
function createDtOverviewBookings(){
document.bookings = new simpleDatatables.DataTable("#bookings", {
searchable: false,
paging: false,
data: {
headings: ["","Datum","Empfänger","Betrag"],
data: bookingdata,
},
rowRender: (row, tr, _index) => {
//tr.childNodes[1].childNodes[0].attributes.href = `editBill/${row.cells[0].data}`;
tr.childNodes[1].attributes.onclick = `location.href='editBill/${row.cells[0].data}'`;
// tr.childNodes[2].attributes.onclick = `collapseDetails(this, ${_index})`;
},
classes: {
active: "active",
disabled: "disabled",
table: "table table-striped table-sm",
},
columns: [
{
select:0,
// render: (data, _cell, _dataIndex, _cellIndex) => { return `<a data-bs-toggle="modal" role="button" data-bs-id="'${data}'" data-bs-target="#mymodal" ><i class="fa-solid fa-trash"></a>` },
cellClass: "datatable-icon",
type: "number",
hidden:true,
},{
select:1,
type: 'date',
format: 'dd.mm.yyyy',
cellClass:"dt-datum",
sortable: true,
sort: "desc",
},{
select:2,
type: 'string',
cellClass:"dt-receiver",
// render: (data, _cell, _dataIndex, _cellIndex) => { return `<a onclick="collapseDetails(this,document.bookings)">${data}</a>` },
},{
select:3,
type: 'number',
headerClass: "dt-amount",
cellClass:"dt-amount",
render: renderAmount
}
],
template: (options, dom) => `<div class='${options.classes.top}'>
<div class='float-start'>
<a class="btn btn-sm btn-secondary" href="newBill">Neue Rechnung</a>
<a class="btn btn-sm btn-secondary" href="newTransfer">Neuer Transfer</a>
</div>
</div>
<div class='${options.classes.container}'${options.scrollY.length ? ` style='height: ${options.scrollY}; overflow-Y: auto;'` : ""}></div>
<div class='${options.classes.bottom}'>
</div>`
});
loadOverviewData();
}
function loadOverviewData(){
document.bookings.setMessage("Loading Data");
fetch("/getOverviewData", { method: "GET",headers: {"X-Requested-With": "XMLHttpRequest"},})
.then(response => {
let status = response.statusText;
if (!response.ok) {
throw "HTTP error: " + response.status + "; " + status;
} else
return response.json();
})
.then(data => {
if (document.bookings.hasRows){
document.bookings.data.data.splice(0,document.bookings.data.data.length);
document.bookings.hasRows = false;
}
//document.bookings.insert({data:data});
document.bookings.insert({data:data.map(item => [item.id,item.datum,item.receiver,item.amount])});
document.bookings.update(true);
})
.catch(err => {
document.bookings.setMessage(err);
});
}
document.addEventListener("DOMContentLoaded", function(event) {
createDtOverviewBookings();
});

View File

@@ -0,0 +1,91 @@
var scheduleddata;
var columnspez = columns;
columnspez.splice(3, 0, { title: "Quelle",orderable:false, data: "source",className:"dt-source" });
function loadScheduledData(){
document.scheduled.setMessage("Loading Data");
fetch("/getScheduledData", { method: "GET",headers: {"X-Requested-With": "XMLHttpRequest"},})
.then(response => response.json())
.then(data => {
if (document.scheduled.hasRows){
document.scheduled.data.data.splice(0,document.scheduled.data.data.length);
document.scheduled.hasRows = false;
}
//document.scheduled.insert({data:data});
document.scheduled.insert({data:data.map(item => [item.id,item.datum,item.receiver,item.source,item.amount])});
document.scheduled.update(true);
});
}
function createDtScheduledBookings(){
document.scheduled = new simpleDatatables.DataTable("#scheduled", {
searchable: true,
paging: false,
classes: {
active: "active",
disabled: "disabled",
table: "table table-striped table-sm",
},
data: {
headings: ["","Datum","Empfänger","Quelle","Betrag"],
data: scheduleddata,
},
rowRender: (row, tr, _index) => {
//tr.childNodes[1].childNodes[0].attributes.href = `editBill/${row.cells[0].data}`;
tr.childNodes[1].attributes.onclick = `location.href='editScheduled/${row.cells[0].data}'`;
// $(row).addClass('text-bg-warning');
// tr.childNodes[2].attributes.onclick = `collapseDetails(this, ${_index})`;
},
columns: [
{
select:0,
render: (data, _cell, _dataIndex, _cellIndex) => { return `<a data-bs-toggle="modal" role="button" data-bs-id="${data}" data-bs-target="#mymodalDelete" ><i class="fa-solid fa-trash"></a>` },
cellClass: "datatable-icon",
type: "number",
sort: "desc",
},{
select:1,
type: 'date',
format: 'dd.mm.yyyy',
cellClass:"dt-datum",
sortable: true,
},{
select:2,
type: 'string',
cellClass:"dt-receiver",
// render: (data, _cell, _dataIndex, _cellIndex) => { return `<a onclick="collapseDetails(this,document.bookings)">${data}</a>` },
},{
select:3,
type: 'string',
cellClass:"dt-source",
// render: (data, _cell, _dataIndex, _cellIndex) => { return `<a onclick="collapseDetails(this,document.bookings)">${data}</a>` },
},{
select:4,
type: 'number',
headerClass: "dt-amount",
cellClass:"dt-amount",
render: renderAmount
}
],
template: (options, dom) => `<div class='${options.classes.top}'>
<div class='float-start'>
<a class="btn btn-sm btn-secondary" href="newScheduled">Neue Auto Rechnung</a>
<a class="btn btn-sm btn-secondary" href="newScheduledTransfer">Neuer Auto Transfer</a>
</div>
<div class='${options.classes.search} float-end'>
<input class='${options.classes.input}' placeholder='Search' type='search' title='${options.labels.searchTitle}'${dom.id ? ` aria-controls="${dom.id}"` : ""}>
</div>
</div>
<div class='${options.classes.container}'${options.scrollY.length ? ` style='height: ${options.scrollY}; overflow-Y: auto;'` : ""}></div>
<div class='${options.classes.bottom}'>
</div>`
});
loadScheduledData();
}
document.addEventListener("DOMContentLoaded", function(event) {
createDtScheduledBookings();
})

99
public/js/tab_todos.js Normal file
View File

@@ -0,0 +1,99 @@
var todosdata;
function loadToDosData(){
document.todos.setMessage("Loading Data");
fetch("/getToDosData", { method: "GET",headers: {"X-Requested-With": "XMLHttpRequest"},})
.then(response => {
let status = response.statusText;
if (!response.ok) {
throw "HTTP error: " + response.status + "; " + status;
} else
return response.json();
})
.then(data => {
if (document.todos.hasRows){
document.todos.data.data.splice(0,document.todos.data.data.length);
document.todos.hasRows = false;
}
document.todos.insert({data:data.map(item => [item.id, item.datum, item.receiver,item.amount])});
document.todos.update(true);
})
.catch(err => {
document.todos.setMessage(err);
});
}
function createDtToDos(){
document.todos = new simpleDatatables.DataTable("#todos", {
searchable: true,
paging: true,
classes: {
active: "active",
disabled: "disabled",
selector: "form-select",
paginationList: "pagination",
paginationListItem: "page-item",
paginationListItemLink: "page-link",
table: "table table-striped table-sm",
},
data: {
headings: ["","Datum","Empfänger","Betrag"],
data: todosdata,
},
rowRender: (row, tr, _index) => {
tr.childNodes[1].attributes.onclick = `location.href='editBill/${row.cells[0].data}'`;
},
columns: [
{
select:0,
// render: (data, _cell, _dataIndex, _cellIndex) => { return `<a data-bs-toggle="modal" role="button" data-bs-id="'${data}'" data-bs-target="#mymodal" ><i class="fa-solid fa-trash"></a>` },
cellClass: "datatable-icon",
type: "number",
hidden:true,
},{
select:1,
type: 'date',
format: 'dd.mm.yyyy',
cellClass:"dt-datum",
sortable: true,
sort: "desc",
},{
select:2,
type: 'string',
cellClass:"dt-receiver",
},{
select:3,
type: 'number',
headerClass: "dt-amount",
cellClass:"dt-amount",
render: renderAmount
}
],
template: (options, dom) => `<div class='${options.classes.top}'>
<div class='float-start'>
<a class="btn btn-sm btn-secondary" data-bs-toggle="modal" role="button" data-bs-target="#mySnycModal" onclick="syncScheduled(this)">Synch</a>
</div>
<div class='${options.classes.search} float-end'>
<input class='${options.classes.input}' placeholder='Search' type='search' title='${options.labels.searchTitle}'${dom.id ? ` aria-controls="${dom.id}"` : ""}>
</div>
</div>
<div class='${options.classes.container}'${options.scrollY.length ? ` style='height: ${options.scrollY}; overflow-Y: auto;'` : ""}></div>
<div class='${options.classes.bottom}'>
<div class='float-start'>
<div class='datatable-dropdown'>
<label>
<select class='${options.classes.selector}'></select>
</label>
</div>
</div>
<div class='float-end'>
<nav class='${options.classes.pagination}'></nav>
</div>
</div>`
});
loadToDosData();
}
document.addEventListener("DOMContentLoaded", function(event) {
createDtToDos();
});

View File

@@ -1,3 +1,11 @@
const renderAmount = function(data, _cell, _dataIndex, _cellIndex) {
var ret = (Number(data)<0)?'<span style="color:red;">':'<span>';
ret += new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(data);
ret += '</span>';
return ret;
}
var colBetrag = {
title: "Betrag",
orderable:false,
@@ -47,29 +55,6 @@ function alert(alertPlaceholder, message, type) {
alertPlaceholder.append(wrapper);
}
function deleteId(id, table) {
if (table == "scheduled")
cmnd = "deleteScheduled";
else
cmnd = "deleteBill";
$.ajax({
type: "POST",
url: "/Ajax/"+cmnd,
data: {"id" : id}, // serializes the form's elements.
success: function(data){
var ph = document.getElementById('alertbox');
alert(ph,"erfolgreich gelöscht",'success');
$('#'+table).DataTable().ajax.reload();
},
error: function(data){
var ph = document.getElementById('alertbox');
alert(ph,"Fehler beim löschen",'danger');
$('#'+table).DataTable().ajax.reload();
}
});
}
function formatDetails ( d ) {
details = '';
str='';
@@ -104,20 +89,22 @@ function formatDetails ( d ) {
// null
// ] )
// } );
function collapseDetails(element, table){
var tr = element.closest('tr');
var row = table.row( tr );
function collapseDetails(e,index){
console.log(e,index);
if ( row.child.isShown() ) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
}
else {
// Open this row
row.child( formatDetails(row.data()) ).show();
tr.addClass('shown');
}
var tr = e.closest('tr');
// var row = table.row( tr );
// if ( row.child.isShown() ) {
// // This row is already open - close it
// row.child.hide();
// tr.removeClass('shown');
// }
// else {
// // Open this row
// row.child( formatDetails(row.data()) ).show();
// tr.addClass('shown');
// }
}
function getId(ele, table) {
@@ -126,21 +113,28 @@ function getId(ele, table) {
return row.data().id;
}
$(document).ready(function(){
document.addEventListener("DOMContentLoaded", function(event) {
var myModal = document.getElementById('mymodal');
const modal = new bootstrap.Modal(myModal);
$("#modal_ok").click(function (e) {
modal.hide();
deleteId(myModal.getAttribute('data-bs-id'), myModal.getAttribute('data-bs-table'));
var myModalDelete = document.getElementById('mymodalDelete');
myModalDelete.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget;
var id = button.getAttribute('data-bs-id');
let tab = button.closest('table').id; // table row ID
myModalDelete.setAttribute('data-bs-id',id);
myModalDelete.setAttribute('data-bs-table',tab);
var modalTitle = myModalDelete.querySelector('.modal-title');
modalTitle.textContent = 'Lösche Eintrag Nr. ' + id;
});
myModal.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget;
table = button.closest('table').id; // table row ID
var id = button.getAttribute('data-bs-id');
let table = button.getAttribute('data-bs-table');
myModal.setAttribute('data-bs-id',id);
myModal.setAttribute('data-bs-table',table);
var modalTitle = myModal.querySelector('.modal-title');
modalTitle.textContent = 'Lösche Eintrag Nr. ' + id;
});
document.getElementById('modal_delete').addEventListener('click', deleteEntry );
});

View File

@@ -1,54 +0,0 @@
var datatable;
var todos;
$(document).ready(function(){
datatable = $('#bookings').DataTable({
paging: false,
searching:true,
scrollX:false,
info:false,
order: [[ 1, 'desc' ]],
ajax: { url: '/Ajax/getOverviewData', dataSrc:''},
layout: {
topStart: {
buttons: [
{text:'Neue Rechnung',className:'btn-sm',action: function ( e, dt, node, config ) {
location.href = '/newBill/';
}},
]
},
topEnd: 'search'
},
// dom: '<"toolbar">frt',
columns: columns,
});
// $("div.toolbar").html('<a class="btn-sm btn-secondary" href="/newBill" role="button">Neuer Eintrag</a>');
// Add event listener for opening and closing details
$('#bookings tbody').on('click', 'td.dt-receiver', function () {collapseDetails($(this), datatable);} );
$('#bookings tbody').on('click', 'td.dt-datum', function () {location.href = '/editBill/'+getId($(this),datatable);});
$('#bookings tbody').on('click', 'table.tabdet', function () {location.href = '/editBill/'+$(this).attr('data-bs-id');});
todos = $('#todos').DataTable({
paging: true,
searching:true,
scrollX:false,
info:true,
order: [[ 1, 'desc' ]],
ajax: { url: '/Ajax/getToDosData', dataSrc:''},
layout: {
topStart: {
buttons: [
{text:'Sync',className:'btn-sm',action: syncScheduled},
]
},
topEnd: 'search'
},
// dom: '<"top"i<"syncbutton">>frt<"bottom"lp><"clear">',
columns: columns,
});
// $("div.syncbutton").html('<a class="btn-sm btn-secondary" href="/syncScheduled" role="button">Sync</a>');
// Add event listener for opening and closing details
$('#todos tbody').on('click', 'td.dt-receiver', function () {collapseDetails($(this), todos);} );
$('#todos tbody').on('click', 'td.dt-datum', function () {location.href = '/editBill/'+getId($(this),todos);});
$('#todos tbody').on('click', 'table.tabdet', function () {location.href = '/editBill/'+$(this).attr('data-bs-id');});
});