making my way downtown~
This commit is contained in:
109
frontend/js/accordion.js
Normal file
109
frontend/js/accordion.js
Normal file
@@ -0,0 +1,109 @@
|
||||
const euroFormat = new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' });
|
||||
|
||||
/**
|
||||
* Erstellt ein Accordion an einem vorgegebenen Punkt, mit einem Inhalt der übergeben wird
|
||||
* @param {DOMElement} rootElement
|
||||
* @param {object} element
|
||||
* @param {DOMElement} body
|
||||
* @param {string} linkName
|
||||
*/
|
||||
export function createAccordion(rootElement, element, body, linkName) {
|
||||
// accordion
|
||||
const accordion = document.createElement("div");
|
||||
accordion.setAttribute("class", "accordion clickable");
|
||||
|
||||
if (body !== null)
|
||||
accordion.setAttribute("class", "accordion clickable");
|
||||
else
|
||||
accordion.setAttribute("class", "accordion");
|
||||
|
||||
// accordion Titel
|
||||
const accordionTitle = document.createElement("div");
|
||||
accordionTitle.setAttribute("class", "accordion-title");
|
||||
|
||||
// accordion Titel Nummer
|
||||
const numberText = document.createElement("div");
|
||||
numberText.innerHTML = element.number;
|
||||
numberText.setAttribute("class", "title-number");
|
||||
accordionTitle.appendChild(numberText);
|
||||
|
||||
// accordion Titel Name
|
||||
const titleText = document.createElement("div");
|
||||
titleText.setAttribute("class", "title-name");
|
||||
|
||||
const titleLink = document.createElement("a");
|
||||
titleLink.innerHTML = element.name;
|
||||
titleLink.setAttribute("class", "title-link");
|
||||
titleLink.href = `html/detail.html?account=${linkName}`;
|
||||
//titleLink.target = "_blank";
|
||||
|
||||
titleText.appendChild(titleLink);
|
||||
accordionTitle.appendChild(titleText);
|
||||
|
||||
// accordion Titel Beschreibung
|
||||
const descriptionText = document.createElement("div");
|
||||
descriptionText.innerHTML = element.description ? element.description : "";
|
||||
descriptionText.setAttribute("class", "title-description");
|
||||
accordionTitle.appendChild(descriptionText);
|
||||
|
||||
// accordion Titel Wert
|
||||
const balanceText = document.createElement("div");
|
||||
balanceText.innerHTML = euroFormat.format(element.balance);
|
||||
|
||||
if (element.balance < 0)
|
||||
balanceText.setAttribute("class", "title-balance negative-number");
|
||||
else if (element.balance > 0)
|
||||
balanceText.setAttribute("class", "title-balance positive-number");
|
||||
else
|
||||
balanceText.setAttribute("class", "title-balance neutral-number");
|
||||
|
||||
accordionTitle.appendChild(balanceText);
|
||||
|
||||
// accordion Anzeige, ob Unterkonten vorhanden
|
||||
const indicatorText = document.createElement("div");
|
||||
indicatorText.innerHTML = element.subaccounts.length > 0 ? "↓" : "";
|
||||
indicatorText.setAttribute("class", "title-indicator");
|
||||
accordionTitle.appendChild(indicatorText);
|
||||
|
||||
// accordion onclick handler
|
||||
accordionTitle.onclick = () => {
|
||||
if (accordion.querySelector(".accordion-content")) {
|
||||
closeAccordion(accordion);
|
||||
} else {
|
||||
const accordions = document.querySelectorAll(".accordion");
|
||||
//accordions.forEach((accordion) => closeAccordion(accordion));
|
||||
if (body !== null) openAccordion(accordion, body);
|
||||
}
|
||||
}
|
||||
|
||||
accordion.appendChild(accordionTitle);
|
||||
rootElement.appendChild(accordion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Öffnet das Accordion
|
||||
* @param {DOMElement} accordion
|
||||
* @param {DOMElement} body
|
||||
*/
|
||||
function openAccordion(accordion, body) {
|
||||
// accordion Inhalt
|
||||
const accordionContent = document.createElement("div");
|
||||
accordionContent.setAttribute("class", "accordion-content");
|
||||
accordionContent.appendChild(body);
|
||||
|
||||
accordion.appendChild(accordionContent);
|
||||
accordion.setAttribute("class", "accordion clickable open");
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Schließt das Accordion
|
||||
* @param {DOMElement} accordion
|
||||
* @param {DOMElement} body
|
||||
*/
|
||||
function closeAccordion(accordion) {
|
||||
accordion.setAttribute("class", "accordion clickable");
|
||||
const content = accordion.querySelector(".accordion-content");
|
||||
if (content)
|
||||
content.remove();
|
||||
};
|
||||
110
frontend/js/account.js
Normal file
110
frontend/js/account.js
Normal file
@@ -0,0 +1,110 @@
|
||||
import { fetchData, postData, putData, deleteData } from "./api.js";
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
let accounts = [];
|
||||
let editAccount = null;
|
||||
|
||||
function start() {
|
||||
fetchData("accounts").then((data) => {
|
||||
extractAccounts(data, "");
|
||||
const selectElement = document.getElementById("account-select");
|
||||
|
||||
accounts.forEach(element => {
|
||||
const option = document.createElement("option");
|
||||
option.text = `${element.id} - ${element.name}`;
|
||||
option.value = element.value;
|
||||
selectElement.append(option);
|
||||
});
|
||||
|
||||
// Prüft ob ein Paramter vorhanden ist, wenn ja dann wird das Konto geladen und die Daten zum bearbeiten befüllt
|
||||
if (urlParams.get('account')) {
|
||||
fetchData(`accounts/${urlParams.get('account')}`).then((data) => {
|
||||
document.getElementById("number").value = data.number;
|
||||
document.getElementById("name").value = data.name;
|
||||
document.getElementById("description").value = data.description ? data.description : "";
|
||||
document.getElementById("type").value = data.type;
|
||||
document.getElementById("account-select").value = data.qualifiedName.replace(`:${data.name}`, "");
|
||||
console.log(data.qualifiedName.replace(`:${data.name}`, ""))
|
||||
editAccount = data;
|
||||
document.getElementById("submit").value = "speichern";
|
||||
document.getElementById("delete").style.display = "block";
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extrahiert die Kontodetails/namen und erstellt dazu ein neues Array
|
||||
* @param {array} data
|
||||
* @param {string} parentName
|
||||
*/
|
||||
function extractAccounts(data, parentName) {
|
||||
data.forEach(element => {
|
||||
let parentAccount = element.name;
|
||||
if (parentName !== "")
|
||||
parentAccount = `${parentName}:${parentAccount}`
|
||||
accounts.push({ id: element.number, name: element.name, value: parentAccount });
|
||||
if (element.subaccounts.length > 0) {
|
||||
extractAccounts(element.subaccounts, parentAccount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Eventhandler um den Vorgang abzubrechen und zurück zu Startseite zu navigieren
|
||||
*/
|
||||
document.getElementById("cancel").addEventListener("click", () => {
|
||||
window.location.href = "../index.html";
|
||||
});
|
||||
|
||||
/**
|
||||
* Eventhandler um ein Konto zu löschen
|
||||
*/
|
||||
document.getElementById("delete").addEventListener("click", () => {
|
||||
if (editAccount && editAccount.entries.length > 0) {
|
||||
alert("Löschen nur möglich, wenn keine Buchungen stattgefunden haben und keine Unterkonten existieren");
|
||||
return;
|
||||
}
|
||||
deleteData(`accounts/${urlParams.get('account')}`).then((response) => {
|
||||
if (response)
|
||||
window.location.href = "../index.html";
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Eventhandler um ein neues Konto anzulegen bzw. das Konto zu bearbeiten
|
||||
*/
|
||||
document.getElementById("submit").addEventListener("click", () => {
|
||||
if (editAccount && editAccount.entries.length > 0) {
|
||||
alert("Accountbearbeitung nur möglich, wenn keine Buchungen stattgefunden haben");
|
||||
return;
|
||||
}
|
||||
|
||||
const number = document.getElementById("number").value;
|
||||
const name = document.getElementById("name").value;
|
||||
const description = document.getElementById("description").value;
|
||||
const type = document.getElementById("type").value;
|
||||
const parentAccount = document.getElementById("account-select").value;
|
||||
|
||||
const data = {
|
||||
"number": Number.parseInt(number),
|
||||
"name": name,
|
||||
"description": description,
|
||||
"type": type,
|
||||
"parentAccount": parentAccount
|
||||
}
|
||||
|
||||
if (editAccount) {
|
||||
putData(`accounts/${urlParams.get('account')}`, data).then((response) => {
|
||||
if (response)
|
||||
window.location.href = "../index.html";
|
||||
});
|
||||
} else {
|
||||
postData("accounts", data).then((response) => {
|
||||
if (response)
|
||||
window.location.href = "../index.html";
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
start();
|
||||
127
frontend/js/api.js
Normal file
127
frontend/js/api.js
Normal file
@@ -0,0 +1,127 @@
|
||||
// API URL
|
||||
// const apiUrl = 'http://149.222.51.77/da4c59b9-43c4-4144-ae39-742c6ba3ad50/api/v1/';
|
||||
const apiUrl = '/api/v1/';
|
||||
|
||||
//SSE URL
|
||||
export const sseUrl = 'http://149.222.51.77/da4c59b9-43c4-4144-ae39-742c6ba3ad50/live';
|
||||
|
||||
export function fetchData(url) {
|
||||
const uri = apiUrl + url;
|
||||
return get(uri);
|
||||
}
|
||||
|
||||
export function postData(url, data) {
|
||||
const uri = apiUrl + url;
|
||||
return post(uri, data);
|
||||
}
|
||||
|
||||
export function putData(url, data) {
|
||||
const uri = apiUrl + url;
|
||||
return put(uri, data);
|
||||
}
|
||||
|
||||
// Make a GET request
|
||||
async function get(url) {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => { alert("Verbindungsprobleme"); controller.abort(); }, 10000);
|
||||
const response = await fetch(url, { signal: controller.signal });
|
||||
|
||||
if (response.ok) {
|
||||
clearTimeout(timeoutId);
|
||||
return response.json();
|
||||
} else {
|
||||
clearTimeout(timeoutId);
|
||||
if (response.status === 400)
|
||||
alert("Ungültige Anfrage");
|
||||
else if (response.status === 404)
|
||||
alert("Transaktion existiert nicht");
|
||||
else (response.status === 500)
|
||||
alert("Unerwarteter Fehler");
|
||||
}
|
||||
}
|
||||
|
||||
// Make a POST request
|
||||
async function post(url, data) {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => { alert("Verbindungsprobleme"); controller.abort(); }, 10000);
|
||||
const response = await fetch(url, {
|
||||
signal: controller.signal,
|
||||
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
|
||||
method: "POST",
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
clearTimeout(timeoutId);
|
||||
alert("Gespeichert!");
|
||||
return true;
|
||||
} else {
|
||||
clearTimeout(timeoutId);
|
||||
if (response.status === 400)
|
||||
alert("Ungültige Anfrage");
|
||||
else if (response.status === 422)
|
||||
alert("Nicht ausführbare Anfrage");
|
||||
else (response.status === 500)
|
||||
alert("Unerwarteter Fehler");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make a PUT request
|
||||
async function put(url, data) {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => { alert("Verbindungsprobleme"); controller.abort(); }, 10000);
|
||||
const response = await fetch(url, {
|
||||
signal: controller.signal,
|
||||
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
|
||||
method: "PUT",
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
clearTimeout(timeoutId);
|
||||
alert("Gespeichert!");
|
||||
return true;
|
||||
} else {
|
||||
clearTimeout(timeoutId);
|
||||
if (response.status === 400)
|
||||
alert("Ungültige Anfrage");
|
||||
else if (response.status === 404)
|
||||
alert("Konto existiert nicht");
|
||||
else if (response.status === 422)
|
||||
alert("Nicht ausführbare Anfrage");
|
||||
else (response.status === 500)
|
||||
alert("Unerwarteter Fehler");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make a DELETE request
|
||||
export async function deleteData(url) {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => { alert("Verbindungsprobleme"); controller.abort(); }, 10000);
|
||||
const response = await fetch(apiUrl + url, {
|
||||
signal: controller.signal,
|
||||
method: "DELETE"
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
clearTimeout(timeoutId);
|
||||
alert("Gelöscht!");
|
||||
return true;
|
||||
} else {
|
||||
clearTimeout(timeoutId);
|
||||
if (response.status === 400)
|
||||
alert("Ungültige Anfrage");
|
||||
else if (response.status === 404)
|
||||
alert("Konto existiert nicht");
|
||||
else if (response.status === 422)
|
||||
alert("Nicht ausführbare Anfrage");
|
||||
else (response.status === 500)
|
||||
alert("Unerwarteter Fehler");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
350
frontend/js/detail.js
Normal file
350
frontend/js/detail.js
Normal file
@@ -0,0 +1,350 @@
|
||||
import { fetchData, deleteData, sseUrl } from "./api.js";
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const euroFormat = new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' });
|
||||
let backendEntries = [];
|
||||
let entries = [];
|
||||
|
||||
// Verbindung zum SSE-Endpunkt herstellen
|
||||
const eventSource = new EventSource(sseUrl);
|
||||
|
||||
// Auf Update reagieren
|
||||
eventSource.addEventListener('update', () => {
|
||||
console.log("refreshing...")
|
||||
start();
|
||||
});
|
||||
|
||||
function start() {
|
||||
fetchData(`accounts/${urlParams.get('account')}`).then((data) => {
|
||||
const root = document.getElementById("detail-container");
|
||||
root.innerHTML = "";
|
||||
|
||||
const title = document.createElement("div");
|
||||
title.innerHTML = `${data.number} - ${data.name}`
|
||||
title.setAttribute("class", "detail-title");
|
||||
root.append(title);
|
||||
|
||||
createDescriptionTable(root, data);
|
||||
|
||||
if (data.description) {
|
||||
const description = document.createElement("div");
|
||||
description.innerHTML = data.description;
|
||||
root.append(description);
|
||||
}
|
||||
|
||||
backendEntries = [...data.entries];
|
||||
entries = [...backendEntries];
|
||||
|
||||
if (entries.length > 0) {
|
||||
document.getElementById("table-container").style.display = "flex";
|
||||
|
||||
//Standardmäßig soll absteigend nach Buchungsdatum sortiert werden
|
||||
entries = entries.sort((a, b) => (a.postingDate < b.postingDate) ? 1 : ((b.postingDate < a.postingDate) ? -1 : 0));
|
||||
//Standardmäßig sollen nur Buchungen des laufenden Kalenderjahres angezeigt werden
|
||||
entries = entries.filter(element => new Date(element.postingDate) >= new Date(new Date().getFullYear(), 0, 1) && new Date(element.valueDate) >= new Date(new Date().getFullYear(), 0, 1));
|
||||
document.getElementById("beginDate").value = `${new Date().getFullYear()}-01-01`;
|
||||
|
||||
createEntryTable(entries);
|
||||
}
|
||||
|
||||
|
||||
if (entries.length < 10)
|
||||
document.getElementById("pagination-div").style.display = "none";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt die Tabelle und errechnet die anzuzeigenden Einträge
|
||||
* @param {array} data
|
||||
*/
|
||||
function createEntryTable(data) {
|
||||
const rootElement = document.querySelector(".table tbody");
|
||||
rootElement.innerHTML = null;
|
||||
|
||||
const bookingDate = document.getElementById("bookingDate");
|
||||
bookingDate.onclick = () => sortTable("postingDate", bookingDate.innerHTML, bookingDate);
|
||||
const valuta = document.getElementById("valuta");
|
||||
valuta.onclick = () => sortTable("valueDate", valuta.innerHTML, valuta);
|
||||
|
||||
const pageInfo = document.getElementById("page-info");
|
||||
const arrayEntriesStart = (pageInfo.innerHTML - 1) * getBookingsPerPage();
|
||||
const arrayEntriesEnd = (pageInfo.innerHTML) * getBookingsPerPage();
|
||||
data = data.slice(arrayEntriesStart, arrayEntriesEnd);
|
||||
|
||||
data.forEach(element => {
|
||||
rootElement.append(createEntryTableRow(element));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt die einzelnen Tabellenzeilen
|
||||
* @param {object} entry
|
||||
* @returns DOMElement
|
||||
*/
|
||||
function createEntryTableRow(entry) {
|
||||
const tr = document.createElement("tr");
|
||||
tr.setAttribute("class", "entry-table-tr");
|
||||
|
||||
const bookingDate = document.createElement("td");
|
||||
bookingDate.setAttribute("class", "entry-table-td");
|
||||
bookingDate.innerHTML = new Date(entry.postingDate).toLocaleDateString("de-DE");
|
||||
tr.append(bookingDate);
|
||||
|
||||
const valuta = document.createElement("td");
|
||||
valuta.setAttribute("class", "entry-table-td");
|
||||
valuta.innerHTML = new Date(entry.valueDate).toLocaleDateString("de-DE");
|
||||
tr.append(valuta);
|
||||
|
||||
const title = document.createElement("td");
|
||||
title.setAttribute("class", "entry-table-td");
|
||||
title.innerHTML = entry.title;
|
||||
tr.append(title);
|
||||
|
||||
const offsetAccount = document.createElement("td");
|
||||
offsetAccount.setAttribute("class", "entry-table-td");
|
||||
offsetAccount.innerHTML = entry.offsetAccounts;
|
||||
tr.append(offsetAccount);
|
||||
|
||||
const amount = document.createElement("td");
|
||||
amount.setAttribute("class", "entry-table-td");
|
||||
amount.innerHTML = euroFormat.format(entry.amount);
|
||||
tr.append(amount);
|
||||
console.log(entry)
|
||||
|
||||
const action = document.createElement("td");
|
||||
action.setAttribute("class", "entry-table-td");
|
||||
action.style.textAlign="center";
|
||||
const editBtn = document.createElement("input");
|
||||
editBtn.setAttribute("class", "action-button-edit");
|
||||
editBtn.type = "button";
|
||||
editBtn.value = "edit";
|
||||
editBtn.onclick = () => window.location.href = `transaction.html?account=${urlParams.get('account')}&id=${entry.id}`;
|
||||
action.append(editBtn);
|
||||
|
||||
const deleteBtn = document.createElement("input");
|
||||
deleteBtn.setAttribute("class", "action-button");
|
||||
deleteBtn.type = "button";
|
||||
deleteBtn.value = "x";
|
||||
deleteBtn.onclick = () => deleteTransaction(entry);
|
||||
action.append(deleteBtn);
|
||||
|
||||
tr.append(action);
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
||||
/**
|
||||
* triggert das löschen der Transaktion
|
||||
* @param {object} transaction
|
||||
*/
|
||||
function deleteTransaction(transaction) {
|
||||
deleteData(`transactions/${transaction.id}`).then(response => {
|
||||
if(response)
|
||||
window.location.reload();
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* navigiert zur Seite, zum anlegen neuer Transaktionen
|
||||
*/
|
||||
document.getElementById("add-transaction").addEventListener("click", () => {
|
||||
window.location.href = `transaction.html?account=${urlParams.get('account')}`
|
||||
});
|
||||
|
||||
/**
|
||||
* Erstellt die Detailtabelle
|
||||
* @param {DOMElement} rootElement
|
||||
* @param {object} data
|
||||
*/
|
||||
function createDescriptionTable(rootElement, data) {
|
||||
const table = document.createElement("table");
|
||||
table.setAttribute("class", "description-table");
|
||||
table.setAttribute("border", "1px");
|
||||
|
||||
if (data.description)
|
||||
table.append(createDescriptionTableRow("Kontoart:", data.type));
|
||||
table.append(createDescriptionTableRow("Bilanz (mit Unterkonten):", euroFormat.format(data.balance)));
|
||||
table.append(createDescriptionTableRow("Bilanz (ohne Unterkonten):", euroFormat.format(data.localBalance)));
|
||||
table.append(createDescriptionTableRow("Aktionen", `<a href="account.html?account=${urlParams.get('account')}" class="edit-link">EDIT</a>`));
|
||||
|
||||
|
||||
rootElement.append(table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt die einzelnen Tabellenzeilen
|
||||
* @param {string} title
|
||||
* @param {string} value
|
||||
* @returns
|
||||
*/
|
||||
function createDescriptionTableRow(title, value) {
|
||||
const accounttype = document.createElement("tr");
|
||||
accounttype.setAttribute("class", "description-table-tr");
|
||||
|
||||
const accounttypeHeader = document.createElement("th");
|
||||
accounttypeHeader.setAttribute("class", "description-table-th");
|
||||
accounttypeHeader.innerHTML = title;
|
||||
|
||||
const accounttypeValue = document.createElement("td");
|
||||
accounttypeValue.setAttribute("class", "description-table-td");
|
||||
accounttypeValue.innerHTML = value;
|
||||
|
||||
accounttype.append(accounttypeHeader);
|
||||
accounttype.append(accounttypeValue);
|
||||
|
||||
return accounttype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eventhandler für das sortieren der Tabellen Datumsspalten
|
||||
* Managed die Pfeile zur Sortierrichtung und sortiert das entries array
|
||||
* @param {string} column
|
||||
* @param {string} columnName
|
||||
* @param {DOMElement} docElement
|
||||
*/
|
||||
function sortTable(column, columnName, docElement) {
|
||||
document.querySelectorAll(".clickable").forEach(element => {
|
||||
if (element.innerHTML.slice(-1) === "↓" || element.innerHTML.slice(-1) === "↑")
|
||||
element.innerHTML = element.innerHTML.slice(0, -1);
|
||||
});
|
||||
|
||||
if (columnName.slice(-1) === "↓") { // ASC
|
||||
docElement.innerHTML = `${docElement.innerHTML.slice(0, columnName.length - 1)}↑`;
|
||||
entries = entries.sort((a, b) => (a[column] > b[column]) ? 1 : ((b[column] > a[column]) ? -1 : 0));
|
||||
} else if (columnName.slice(-1) === "↑") { // default
|
||||
docElement.innerHTML = `${docElement.innerHTML.slice(0, columnName.length - 1)}`;
|
||||
entries = backendEntries;
|
||||
} else { // DESC
|
||||
docElement.innerHTML = `${docElement.innerHTML} ↓`;
|
||||
entries = entries.sort((a, b) => (a[column] < b[column]) ? 1 : ((b[column] < a[column]) ? -1 : 0));
|
||||
}
|
||||
|
||||
createEntryTable(entries);
|
||||
}
|
||||
// Fügt den Eventhandler für die Filter Eingabefelder hinzu
|
||||
document.getElementsByName("dateFilter").forEach(element => element.addEventListener("change", filterAll));
|
||||
document.getElementsByName("textFilter").forEach(element => element.addEventListener("keyup", filterAll));
|
||||
|
||||
// Eventhandler um die Datumsfelder zurückzusetzen
|
||||
document.getElementById("resetDates").addEventListener("click", () => {
|
||||
document.getElementById("beginDate").value = "";
|
||||
document.getElementById("endDate").value = "";
|
||||
filterAll();
|
||||
});
|
||||
|
||||
/**
|
||||
* Filtert die Daten aus dem Backend nach den Filterfeldern
|
||||
*/
|
||||
function filterAll() {
|
||||
let filteredEntries = backendEntries;
|
||||
filteredEntries = filterDates(filteredEntries);
|
||||
filteredEntries = filterText(filteredEntries);
|
||||
filteredEntries = filterAmount(filteredEntries);
|
||||
|
||||
createEntryTable(filteredEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtert die Daten anhand der Datumsfelder
|
||||
* @param {array} array
|
||||
* @returns array
|
||||
*/
|
||||
function filterDates(array) {
|
||||
const begin = document.getElementById("beginDate").value;
|
||||
const end = document.getElementById("endDate").value;
|
||||
|
||||
if (begin !== "" && end !== "") {
|
||||
return array.filter(element => (new Date(element.postingDate) >= new Date(begin) && new Date(element.valueDate) >= new Date(begin)) && (new Date(element.postingDate) <= new Date(end) && new Date(element.valueDate) <= new Date(end)));
|
||||
} else if (begin !== "") {
|
||||
return array.filter(element => new Date(element.postingDate) >= new Date(begin) && new Date(element.valueDate) >= new Date(begin));
|
||||
} else if (end !== "") {
|
||||
return array.filter(element => new Date(element.postingDate) <= new Date(end) && new Date(element.valueDate) <= new Date(end));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtert die Daten anhand der des Freitextfeldes
|
||||
* @param {array} array
|
||||
* @returns array
|
||||
*/
|
||||
function filterText(array) {
|
||||
const searchString = document.getElementById("searchText").value;
|
||||
if (searchString !== "") {
|
||||
return array.filter(element => element.title.toLowerCase().includes(searchString.toLowerCase()));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtert die Daten anhand der des min. und max. Betrags
|
||||
* @param {array} array
|
||||
* @returns array
|
||||
*/
|
||||
function filterAmount(array) {
|
||||
const begin = document.getElementById("beginAmount").value;
|
||||
const end = document.getElementById("endAmount").value;
|
||||
|
||||
if (begin !== "" && end !== "") {
|
||||
return array.filter(element => (element.amount >= begin) && (element.amount <= end));
|
||||
} else if (begin !== "") {
|
||||
return array.filter(element => element.amount >= begin);
|
||||
} else if (end !== "") {
|
||||
return array.filter(element => element.amount <= end);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eventhandler für Pagination "Seite Vorwärts Button"
|
||||
*/
|
||||
document.getElementById("forward-page").addEventListener("click", () => {
|
||||
const pageInfo = document.getElementById("page-info");
|
||||
let pageNumber = ++pageInfo.innerHTML;
|
||||
const maxPage = Math.ceil(entries.length / getBookingsPerPage());
|
||||
|
||||
if (pageNumber > maxPage)
|
||||
pageNumber = 1;
|
||||
|
||||
pageInfo.innerHTML = pageNumber;
|
||||
createEntryTable(entries);
|
||||
});
|
||||
|
||||
/**
|
||||
* Eventhandler für Pagination "Seite Rückwärts Button"
|
||||
*/
|
||||
document.getElementById("backward-page").addEventListener("click", () => {
|
||||
const pageInfo = document.getElementById("page-info");
|
||||
let pageNumber = --pageInfo.innerHTML;
|
||||
const maxPage = Math.ceil(entries.length / getBookingsPerPage());
|
||||
|
||||
if (pageNumber < 1)
|
||||
pageNumber = maxPage;
|
||||
|
||||
pageInfo.innerHTML = pageNumber;
|
||||
createEntryTable(entries);
|
||||
});
|
||||
|
||||
/**
|
||||
* Eventhandler für Selectbox Änderung
|
||||
*/
|
||||
document.getElementById("table-range").addEventListener("change", () => {
|
||||
document.getElementById("page-info").innerHTML = 1; //reset page
|
||||
createEntryTable(entries);
|
||||
});
|
||||
|
||||
/**
|
||||
* Liefert die Anzahl der Einträge aus der Selectbox zurück bzw. die Array länge, bei Auswahl von "Alle"
|
||||
* @returns integer
|
||||
*/
|
||||
function getBookingsPerPage() {
|
||||
if (document.getElementById("table-range").value === "Alle")
|
||||
return entries.length;
|
||||
|
||||
return Number.parseInt(document.getElementById("table-range").value);
|
||||
}
|
||||
|
||||
start();
|
||||
214
frontend/js/overview.js
Normal file
214
frontend/js/overview.js
Normal file
@@ -0,0 +1,214 @@
|
||||
import { fetchData, sseUrl } from "./api.js";
|
||||
|
||||
let backendEntries = [];
|
||||
let entries = [];
|
||||
|
||||
// Verbindung zum SSE-Endpunkt herstellen
|
||||
const eventSource = new EventSource(sseUrl);
|
||||
|
||||
// Auf Update reagieren
|
||||
eventSource.addEventListener('update', () => {
|
||||
console.log("refreshing...")
|
||||
start();
|
||||
});
|
||||
|
||||
function start() {
|
||||
fetchData(`transactions`).then((data) => {
|
||||
backendEntries = [...data];
|
||||
entries = [...backendEntries];
|
||||
|
||||
if (entries.length > 0) {
|
||||
document.getElementById("table-container").style.display = "flex";
|
||||
|
||||
createTableBody(entries);
|
||||
}
|
||||
|
||||
if (entries.length < 10)
|
||||
document.getElementById("pagination-div").style.display = "none";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generiert den Tabelleninhalt
|
||||
* Anhand der angaben aus Seitenzahl und Zeilenangaben werden entsprechend viele Zeilen erstellt
|
||||
* @param {array} data
|
||||
*/
|
||||
function createTableBody(data) {
|
||||
const rootElement = document.querySelector(".table tbody");
|
||||
rootElement.innerHTML = null;
|
||||
|
||||
const bookingDate = document.getElementById("bookingDate");
|
||||
bookingDate.onclick = () => sortTable("postingDate", bookingDate.innerHTML, bookingDate);
|
||||
const valuta = document.getElementById("valuta");
|
||||
valuta.onclick = () => sortTable("valueDate", valuta.innerHTML, valuta);
|
||||
|
||||
const pageInfo = document.getElementById("page-info");
|
||||
const arrayEntriesStart = (pageInfo.innerHTML-1) * getBookingsPerPage();
|
||||
const arrayEntriesEnd = (pageInfo.innerHTML) * getBookingsPerPage();
|
||||
data = data.slice(arrayEntriesStart, arrayEntriesEnd);
|
||||
|
||||
data.forEach(element => {
|
||||
rootElement.append(createEntryTableRow(element));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt die einzelne Tabellenzeile
|
||||
* @param {object} entry
|
||||
* @returns DOMElement
|
||||
*/
|
||||
function createEntryTableRow(entry) {
|
||||
const tr = document.createElement("tr");
|
||||
tr.setAttribute("class", "entry-table-tr");
|
||||
|
||||
const bookingDate = document.createElement("td");
|
||||
bookingDate.setAttribute("class", "entry-table-td");
|
||||
bookingDate.innerHTML = new Date(entry.postingDate).toLocaleDateString("de-DE");
|
||||
tr.append(bookingDate);
|
||||
|
||||
const valuta = document.createElement("td");
|
||||
valuta.setAttribute("class", "entry-table-td");
|
||||
valuta.innerHTML = new Date(entry.valueDate).toLocaleDateString("de-DE");
|
||||
tr.append(valuta);
|
||||
|
||||
const title = document.createElement("td");
|
||||
title.setAttribute("class", "entry-table-td");
|
||||
title.innerHTML = entry.title;
|
||||
tr.append(title);
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eventhandler für das sortieren der Tabellen Datumsspalten
|
||||
* Managed die Pfeile zur Sortierrichtung und sortiert das entries array
|
||||
* @param {string} column
|
||||
* @param {string} columnName
|
||||
* @param {DOMElement} docElement
|
||||
*/
|
||||
function sortTable(column, columnName, docElement) {
|
||||
document.querySelectorAll(".clickable").forEach(element => {
|
||||
if(element.innerHTML.slice(-1) === "↓" || element.innerHTML.slice(-1) === "↑")
|
||||
element.innerHTML = element.innerHTML.slice(0, -1);
|
||||
});
|
||||
|
||||
if (columnName.slice(-1) === "↓") { // ASC
|
||||
docElement.innerHTML = `${columnName.slice(0, columnName.length - 1)}↑`;
|
||||
entries = entries.sort((a, b) => (a[column] > b[column]) ? 1 : ((b[column] > a[column]) ? -1 : 0));
|
||||
} else if (columnName.slice(-1) === "↑") { // default
|
||||
docElement.innerHTML = `${columnName.slice(0, columnName.length - 1)}`;
|
||||
entries = backendEntries;
|
||||
} else { // DESC
|
||||
docElement.innerHTML = `${columnName} ↓`;
|
||||
entries = entries.sort((a, b) => (a[column] < b[column]) ? 1 : ((b[column] < a[column]) ? -1 : 0));
|
||||
}
|
||||
|
||||
createTableBody(entries);
|
||||
}
|
||||
|
||||
// Fügt den Eventhandler für die Filter Eingabefelder hinzu
|
||||
document.getElementsByName("dateFilter").forEach(element => element.addEventListener("change", filterAll));
|
||||
document.getElementsByName("textFilter").forEach(element => element.addEventListener("keyup", filterAll));
|
||||
|
||||
// Eventhandler um die Datumsfelder zurückzusetzen
|
||||
document.getElementById("resetDates").addEventListener("click", () => {
|
||||
document.getElementById("beginDate").value = "";
|
||||
document.getElementById("endDate").value = "";
|
||||
filterAll();
|
||||
});
|
||||
|
||||
/**
|
||||
* Filtert die Daten aus dem Backend nach den Filterfeldern
|
||||
*/
|
||||
function filterAll() {
|
||||
let filteredEntries = backendEntries;
|
||||
filteredEntries = filterDates(filteredEntries);
|
||||
filteredEntries = filterText(filteredEntries);
|
||||
|
||||
createTableBody(filteredEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtert die Daten anhand der Datumsfelder
|
||||
* @param {array} array
|
||||
* @returns array
|
||||
*/
|
||||
function filterDates(array) {
|
||||
const begin = document.getElementById("beginDate").value;
|
||||
const end = document.getElementById("endDate").value;
|
||||
|
||||
if (begin !== "" && end !== "") {
|
||||
return array.filter(element => (new Date(element.postingDate) >= new Date(begin) && new Date(element.valueDate) >= new Date(begin)) && (new Date(element.postingDate) <= new Date(end) && new Date(element.valueDate) <= new Date(end)));
|
||||
} else if (begin !== "") {
|
||||
return array.filter(element => new Date(element.postingDate) >= new Date(begin) && new Date(element.valueDate) >= new Date(begin));
|
||||
} else if (end !== "") {
|
||||
return array.filter(element => new Date(element.postingDate) <= new Date(end) && new Date(element.valueDate) <= new Date(end));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtert die Daten anhand der des Freitextfeldes
|
||||
* @param {array} array
|
||||
* @returns array
|
||||
*/
|
||||
function filterText(array) {
|
||||
const searchString = document.getElementById("searchText").value;
|
||||
if (searchString !== "") {
|
||||
return array.filter(element => element.title.toLowerCase().includes(searchString.toLowerCase()));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eventhandler für Pagination "Seite Vorwärts Button"
|
||||
*/
|
||||
document.getElementById("forward-page").addEventListener("click", () => {
|
||||
const pageInfo = document.getElementById("page-info");
|
||||
let pageNumber = ++pageInfo.innerHTML;
|
||||
const maxPage = Math.ceil(entries.length / getBookingsPerPage());
|
||||
|
||||
if(pageNumber > maxPage)
|
||||
pageNumber = 1;
|
||||
|
||||
pageInfo.innerHTML = pageNumber;
|
||||
createTableBody(entries);
|
||||
});
|
||||
|
||||
/**
|
||||
* Eventhandler für Pagination "Seite Rückwärts Button"
|
||||
*/
|
||||
document.getElementById("backward-page").addEventListener("click", () => {
|
||||
const pageInfo = document.getElementById("page-info");
|
||||
let pageNumber = --pageInfo.innerHTML;
|
||||
const maxPage = Math.ceil(entries.length / getBookingsPerPage());
|
||||
|
||||
if(pageNumber < 1)
|
||||
pageNumber = maxPage;
|
||||
|
||||
pageInfo.innerHTML = pageNumber;
|
||||
createTableBody(entries);
|
||||
});
|
||||
|
||||
/**
|
||||
* Eventhandler für Selectbox Änderung
|
||||
*/
|
||||
document.getElementById("table-range").addEventListener("change", () => {
|
||||
document.getElementById("page-info").innerHTML = 1; //reset page
|
||||
createTableBody(entries);
|
||||
});
|
||||
|
||||
/**
|
||||
* Liefert die Anzahl der Einträge aus der Selectbox zurück bzw. die Array länge, bei Auswahl von "Alle"
|
||||
* @returns integer
|
||||
*/
|
||||
function getBookingsPerPage() {
|
||||
if(document.getElementById("table-range").value === "Alle")
|
||||
return entries.length;
|
||||
|
||||
return Number.parseInt(document.getElementById("table-range").value);
|
||||
}
|
||||
|
||||
start();
|
||||
178
frontend/js/transaction.js
Normal file
178
frontend/js/transaction.js
Normal file
@@ -0,0 +1,178 @@
|
||||
import { fetchData, postData, putData } from "./api.js";
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
let accounts = [];
|
||||
let account = null;
|
||||
let transaction = null;
|
||||
|
||||
function start() {
|
||||
fetchData("accounts").then((data) => {
|
||||
extractAccounts(data, "");
|
||||
|
||||
if (urlParams.get('account')) {
|
||||
fetchData(`accounts/${urlParams.get('account')}`).then((data) => {
|
||||
account = data;
|
||||
|
||||
if (urlParams.get('id')) {
|
||||
fetchData(`transactions/${urlParams.get('id')}`).then((transactionData) => {
|
||||
transaction = transactionData;
|
||||
console.log(transaction)
|
||||
|
||||
document.getElementById("submit").value = "bearbeiten";
|
||||
document.getElementById("postingDate").value = transaction.postingDate;
|
||||
document.getElementById("valueDate").value = transaction.valueDate;
|
||||
document.getElementById("title").value = transaction.title;
|
||||
|
||||
transaction.entries.forEach(entry => {
|
||||
addTableRow(entry);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* extract account hierarchy and create arraylist of all accounts
|
||||
* @param {array} data
|
||||
* @param {string} parentName
|
||||
*/
|
||||
function extractAccounts(data, parentName) {
|
||||
data.forEach(element => {
|
||||
let parentAccount = element.name;
|
||||
if (parentName !== "")
|
||||
parentAccount = `${parentName}:${parentAccount}`
|
||||
accounts.push({ id: element.number, name: element.name, value: parentAccount });
|
||||
if (element.subaccounts.length > 0) {
|
||||
extractAccounts(element.subaccounts, parentAccount);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Eventhandler um Tabellenzeilen mit leeren Textfeldern hinzuzufügen
|
||||
*/
|
||||
document.getElementById("add-transaction").addEventListener("click", () => {
|
||||
addTableRow();
|
||||
});
|
||||
|
||||
/**
|
||||
* Fügt eine neue Tabellenzeile mit leeren Textfeldern hinzu
|
||||
* @param {array} data
|
||||
*/
|
||||
function addTableRow(data) {
|
||||
const table = document.querySelector(".transaction-table tbody");
|
||||
const tr = document.createElement("tr");
|
||||
tr.className = "transaction-tr";
|
||||
|
||||
const accountTd = document.createElement("td");
|
||||
accountTd.className = "transaction-td";
|
||||
const accountSelect = createAccountSelect()
|
||||
accountTd.appendChild(accountSelect);
|
||||
|
||||
const amountTd = document.createElement("td");
|
||||
amountTd.className = "transaction-td";
|
||||
const amountInput = document.createElement("input");
|
||||
amountInput.className = "transaction-input";
|
||||
amountInput.type = "number";
|
||||
amountInput.name = "amount";
|
||||
amountTd.appendChild(amountInput);
|
||||
|
||||
const bookingTextTd = document.createElement("td");
|
||||
bookingTextTd.className = "transaction-td";
|
||||
const bookingInput = document.createElement("input");
|
||||
bookingInput.className = "transaction-input";
|
||||
bookingInput.name = "text";
|
||||
bookingTextTd.appendChild(bookingInput);
|
||||
|
||||
const actionTd = document.createElement("td");
|
||||
actionTd.className = "transaction-td";
|
||||
const actionButton = document.createElement("input");
|
||||
actionButton.className = "action-button";
|
||||
actionButton.type = "button";
|
||||
actionButton.value = "x";
|
||||
actionButton.onclick = () => tr.remove();
|
||||
actionTd.appendChild(actionButton);
|
||||
|
||||
if(data) {
|
||||
accountSelect.value = data.account;
|
||||
amountInput.value = data.amount;
|
||||
bookingInput.value = data.label;
|
||||
}
|
||||
|
||||
tr.appendChild(accountTd);
|
||||
tr.appendChild(amountTd);
|
||||
tr.appendChild(bookingTextTd);
|
||||
tr.appendChild(actionTd);
|
||||
table.append(tr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erstellt die Selectbox für Kontenauswahl
|
||||
* @returns DOMElement
|
||||
*/
|
||||
function createAccountSelect() {
|
||||
const selectElement = document.createElement("select");
|
||||
selectElement.className = "transaction-input";
|
||||
selectElement.name = "account";
|
||||
|
||||
const option = document.createElement("option");
|
||||
option.text = "--- Konto wählen ---";
|
||||
option.disabled = true;
|
||||
option.selected = true;
|
||||
selectElement.append(option);
|
||||
|
||||
accounts.forEach(element => {
|
||||
const option = document.createElement("option");
|
||||
option.text = `${element.id} - ${element.value}`;
|
||||
option.value = element.value;
|
||||
selectElement.append(option);
|
||||
});
|
||||
|
||||
return selectElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eventhandler für das abbrechen und zurücknavigieren zur Homepage
|
||||
*/
|
||||
document.getElementById("cancel").addEventListener("click", () => {
|
||||
window.location.href = "../index.html";
|
||||
});
|
||||
|
||||
/**
|
||||
* Eventhandeler zum senden der Transaktionsdaten
|
||||
* Liest die Werte aus den Eingabefenstern, erzeugt das Objekt und sendet sie zur API
|
||||
*/
|
||||
document.getElementById("submit").addEventListener("click", () => {
|
||||
const postingDate = document.getElementById("postingDate").value;
|
||||
const valueDate = document.getElementById("valueDate").value;
|
||||
const title = document.getElementById("title").value;
|
||||
|
||||
const data = {
|
||||
"postingDate": postingDate,
|
||||
"valueDate": valueDate,
|
||||
"title": title,
|
||||
"entries": []
|
||||
}
|
||||
|
||||
document.querySelectorAll(".transaction-table tbody tr").forEach(tr => {
|
||||
const account = tr.querySelector("[name=account]").value;
|
||||
const amount = Number.parseFloat(tr.querySelector("[name=amount]").value);
|
||||
const text = tr.querySelector("[name=text]").value;
|
||||
data.entries.push({ account: account, amount: amount, label: text });
|
||||
});
|
||||
|
||||
if(transaction) {
|
||||
putData(`transactions/${urlParams.get('id')}`, data).then((response) => {
|
||||
if (response)
|
||||
window.location.href = `./detail.html?account=${urlParams.get('account')}`;
|
||||
});
|
||||
} else {
|
||||
postData("transactions", data).then((response) => {
|
||||
if (response)
|
||||
window.location.href = `./detail.html?account=${urlParams.get('account')}`;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
start();
|
||||
Reference in New Issue
Block a user