-
Notifications
You must be signed in to change notification settings - Fork 0
/
BudgetTracker.js
143 lines (122 loc) · 4.74 KB
/
BudgetTracker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
export default class BudgetTracker {
constructor(querySelectorString) {
this.root = document.querySelector(querySelectorString);
this.root.innerHTML = BudgetTracker.html();
this.root.querySelector(".new-entry").addEventListener("click", () => {
this.onNewEntryBtnClick();
});
// Load Initial data from Local Storage
this.load();
}
static html(){
return `
<table class="budget-tracker">
<thead>
<tr>
<th>Date</th>
<th>Description</th>
<th>Type</th>
<th>Amount</th>
<th></th>
</tr>
</thead>
<tbody class="entries"></tbody>
<tbody>
<tr>
<td colspan="5" class="controls">
<button type="button" class="new-entry">New Entry</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" class="summary">
<strong>Total:</strong>
<span class="total">0.00€</span>
</td>
</tr>
</tfoot>
</table>
`;
}
static entryHtml() {
return `
<tr>
<td>
<input class="input input-date" type="date">
</td>
<td>
<input class="input input-description" type="text" placeholder="Add a Description (e.g. wages, bills, etc.)">
</td>
<td>
<select class="input input-type">
<option value="income">Income</option>
<option value="expense">Expense</option>
</select>
</td>
<td>
<input type="number" class="input input-amount">
</td>
<td>
<button type="button" class="delete-entry">✕</button>
</td>
</tr>
`;
}
load() {
const entries = JSON.parse(localStorage.getItem("budget-tracker-entries") || "[]");
for (const entry of entries) {
this.addEntry(entry);
}
this.updateSummary();
}
updateSummary() {
const total = this.getEntryRows().reduce((total, row) => {
const amount = row.querySelector(".input-amount").value;
const isExpense = row.querySelector(".input-type").value === "expense";
const modifier = isExpense ? -1 : 1;
return total + (amount * modifier);
}, 0);
const totalFormatted = new Intl.NumberFormat("el-GR", {
style: "currency",
currency: "EUR"
}).format(total);
this.root.querySelector(".total").textContent = totalFormatted;
}
save() {
const data = this.getEntryRows().map(row => {
return {
date: row.querySelector(".input-date").value,
description: row.querySelector(".input-description").value,
type: row.querySelector(".input-type").value,
amount: parseFloat(".input-amount").value,
};
});
localStorage.setItem("budget-tracker-entries", JSON.stringify(data));
this.updateSummary();
}
addEntry(entry = {}) {
this.root.querySelector(".entries").insertAdjacentHTML("beforeend", BudgetTracker.entryHtml());
const row = this.root.querySelector(".entries tr:last-of-type");
row.querySelector(".input-date").value = entry.date || new Date().toISOString().replace(/T.*/, "");
row.querySelector(".input-description").value = entry.description || "";
row.querySelector(".input-type").value = entry.type || "income";
row.querySelector(".input-amount").value = entry.amount || 0;
row.querySelector(".delete-entry").addEventListener("click", e => {
this.onDeleteEntryBtnClick(e);
});
row.querySelectorAll(".input").forEach(input => {
input.addEventListener("change", () => this.save());
});
}
getEntryRows() {
return Array.from(this.root.querySelectorAll(".entries tr"));
}
onNewEntryBtnClick() {
this.addEntry();
}
onDeleteEntryBtnClick(e) {
e.target.closest("tr").remove();
this.save();
}
}