diff options
Diffstat (limited to 'public/projects/js-small-apps/budget-app/app.js')
| -rw-r--r-- | public/projects/js-small-apps/budget-app/app.js | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/public/projects/js-small-apps/budget-app/app.js b/public/projects/js-small-apps/budget-app/app.js new file mode 100644 index 0000000..2fb0cba --- /dev/null +++ b/public/projects/js-small-apps/budget-app/app.js @@ -0,0 +1,311 @@ +import BudgetApp from "./lib/class-budget-app.js"; +import Notification from "./lib/class-notification.js"; +import getCurrencyFormat from "./lib/utils/currency.js"; + +const app = new BudgetApp("Budget", "Anonymous"); +const ui = { + budget: { + remaining: document.getElementById("budget-remaining"), + spent: document.getElementById("budget-spent"), + }, + buttons: { + categories: { + add: document.querySelector(".manage-categories .btn--add"), + delete: document.querySelector(".manage-categories .btn--delete"), + rename: document.querySelector(".manage-categories .btn--rename"), + }, + register: document.querySelector(".register .btn--register"), + reset: document.querySelector(".footer .btn--reset"), + transactions: { + update: document.querySelector(".manage-transactions .btn--update"), + }, + }, + form: { + categories: { + add: document.getElementById("add-category"), + rename: document.getElementById("rename-category"), + select: document.getElementById("select-category"), + }, + register: { + budget: document.getElementById("register-budget"), + language: document.getElementById("register-locale"), + username: document.getElementById("register-username"), + }, + transactions: { + amount: document.getElementById("transaction-amount"), + category: document.getElementById("transaction-category"), + date: document.getElementById("transaction-date"), + id: document.getElementById("transaction-id"), + name: document.getElementById("transaction-name"), + type: document.getElementById("transaction-type"), + }, + }, + history: { + body: document.querySelector(".app__history .table__body"), + }, + title: document.querySelector(".branding__title"), +}; + +function initApp() { + const register = document.querySelector(".register"); + const application = document.querySelector(".app"); + const budget = ui.form.register.budget.value; + const locale = ui.form.register.language.value; + const username = ui.form.register.username.value; + + if (budget && locale && username) { + app.user.username = username; + app.user.budget = budget; + app.user.locale = locale; + register.style.display = "none"; + application.style.display = "block"; + } else { + notify("You must complete all fields!", "error", 3000); + } +} + +function notify(message, type, duration, position = "bottom") { + const notification = new Notification(message, type); + notification.duration = duration; + notification.position = position; + return notification.notify(); +} + +function getSelectOptions(select, options) { + select.innerHTML = ""; + options.forEach((option) => { + select.add(new Option(option.name, option.id)); + }); + + return select; +} + +function findName(id, array) { + const object = array.find((item) => item.id === Number(id)); + if (object) { + return object.name; + } else { + return "(deleted)"; + } +} + +function resetTransactionForm() { + ui.form.transactions.amount.value = ""; + ui.form.transactions.category.value = ""; + ui.form.transactions.date.value = ""; + ui.form.transactions.id.value = ""; + ui.form.transactions.name.value = ""; + ui.form.transactions.type.value = ""; +} + +function setTransactionForm(transaction) { + ui.form.transactions.amount.value = transaction.amount; + ui.form.transactions.category.value = transaction.category; + ui.form.transactions.date.valueAsDate = transaction.date; + ui.form.transactions.id.value = transaction.id; + ui.form.transactions.name.value = transaction.name; + ui.form.transactions.type.value = transaction.type; +} + +function manageHistory(target) { + const tr = target.parentElement.parentElement; + const transactionId = Number(tr.id.replace("transaction-", "")); + const array = tr.classList.contains("table__row--expense") + ? app.expenses + : app.incomes; + if (target.classList.contains("btn--delete")) { + const tbody = tr.parentElement; + app.remove(transactionId, array); + updateBudget(); + updateHistory(tbody); + } else if (target.classList.contains("btn--edit")) { + const index = array.findIndex( + (transaction) => transaction.id === transactionId + ); + setTransactionForm(array[index]); + } +} + +function getTransactionButton(type) { + const btn = document.createElement("button"); + let text = ""; + + switch (type) { + case "delete": + text = "Delete"; + break; + case "edit": + text = "Edit"; + break; + default: + break; + } + + btn.textContent = text; + btn.classList.add("btn", `btn--${type}`); + btn.addEventListener("click", (event) => manageHistory(event.target)); + + return btn; +} + +function getTransactionCell(data = "") { + const td = document.createElement("td"); + td.classList.add("table__item"); + td.textContent = data; + + return td; +} + +function getTransactionRow(transaction) { + const tr = document.createElement("tr"); + const amount = + transaction.type === "expense" + ? transaction.amount * -1 + : transaction.amount; + const localizedAmount = getCurrencyFormat(amount, app.user.locale); + const categoryName = findName(transaction.category, app.categories); + const date = transaction.date.toLocaleDateString(app.user.locale); + + const dateCell = getTransactionCell(date); + const nameCell = getTransactionCell(transaction.name); + const categoryCell = getTransactionCell(categoryName); + const typeCell = getTransactionCell(transaction.type); + const amountCell = getTransactionCell(localizedAmount); + const manageCell = getTransactionCell(); + const editButton = getTransactionButton("edit"); + const deleteButton = getTransactionButton("delete"); + + manageCell.append(editButton, deleteButton); + tr.classList.add("table__row", `table__row--${transaction.type}`); + tr.id = `transaction-${transaction.id}`; + tr.append(dateCell, nameCell, categoryCell, typeCell, amountCell, manageCell); + + return tr; +} + +function getHistory(tbody) { + const transactions = app.getOrderedTransactions("oldest"); + transactions.forEach((transaction) => { + tbody.appendChild(getTransactionRow(transaction)); + }); +} + +function updateBudget() { + app.updateUserBudget(); + ui.budget.remaining.textContent = getCurrencyFormat( + app.user.budget.remaining(), + app.user.locale + ); + ui.budget.spent.textContent = getCurrencyFormat( + app.user.budget.spent, + app.user.locale + ); +} + +function updateCategories() { + getSelectOptions(ui.form.categories.select, app.categories); + getSelectOptions(ui.form.transactions.category, app.categories); +} + +function updateHistory() { + ui.history.body.innerHTML = ""; + getHistory(ui.history.body, app); +} + +function updateAll() { + ui.title.textContent = `${app.user.username} ${app.title}`; + updateBudget(); + updateCategories(); + updateHistory(); +} + +function listen() { + for (const [name, element] of Object.entries(ui.buttons.categories)) { + element.addEventListener("click", (event) => { + event.preventDefault(); + const id = Number(ui.form.categories.select.value); + + switch (name) { + case "add": + if (ui.form.categories.add.value) { + app.addCategory(ui.form.categories.add.value); + ui.form.categories.add.value = ""; + } else { + notify("Category name must be filled!", "error", 3000); + } + break; + case "delete": + if (id) { + app.remove(id, app.categories); + updateHistory(); + } else { + notify("A category must be selected!", "error", 3000); + } + break; + case "rename": + const newName = ui.form.categories.rename.value; + if (newName && id) { + app.renameCategory(id, newName); + updateHistory(); + ui.form.categories.rename.value = ""; + } else { + notify( + "You need to select a category and enter a new name first!", + "error", + 3000 + ); + } + break; + default: + break; + } + + updateCategories(); + }); + } + + ui.buttons.transactions.update.addEventListener("click", (event) => { + event.preventDefault(); + const transactionId = Number(ui.form.transactions.id.value); + const transaction = { + date: ui.form.transactions.date.value, + name: ui.form.transactions.name.value, + type: ui.form.transactions.type.value, + category: ui.form.transactions.category.value, + amount: ui.form.transactions.amount.value, + }; + const error = []; + for (const value in transaction) { + const element = transaction[value]; + !element ? error.push(value) : ""; + } + if (error.length === 0) { + transactionId + ? app.editTransaction({ id: transactionId, ...transaction }) + : app.addTransaction(transaction); + updateBudget(); + updateHistory(); + resetTransactionForm(); + } else { + const errorMsg = `These fields (${error.join(", ")}) must be filled!`; + notify(errorMsg, "error", 3000); + } + }); + + ui.buttons.register.addEventListener("click", (event) => { + event.preventDefault(); + initApp(); + updateAll(); + }); + + ui.buttons.reset.addEventListener("click", (event) => { + event.preventDefault(); + if (confirm("Are you sure?")) { + notify("Reset!", "warning", 2000); + app.reset(); + } + updateAll(); + }); +} + +listen(); |
