const View = require(__dirname + '/view.js');
const {timestampToString} = require(__dirname + '/../utils/dateHandler.js');
/**
* Class for controlling the startpage of the application.
*/
class IndexView extends View {
/**
* @param {Storage} storage Storage object.
*/
constructor(storage) {
super(storage);
}
/**
* Updates the view.
*/
updateView() {
this.displayBudgets('#currentBudgets');
this.displayRecurrTrans('#recurrTrans');
this.displayBalances('#currentBalances');
this.displayRecentTransactions('#recentSpendings', 'spending');
this.displayRecentTransactions('#recentEarnings', 'earning');
}
/**
* Displays all currently available budgets in a simple overview.
*
* @param {string} id The id of the dom element which contains the budget display.
*/
displayBudgets(id) {
let headings = [
this.textData['budget'],
this.textData['balance'],
this.textData['edit']
];
if (this.storage.readMainStorage('allocationOn')) {
headings.push(this.textData['allocationRatio']);
}
let budgets = this.storage.readMainStorage('budgets');
let rows = budgets.map(b => [
b[0], // Index 0: name of the budget.
this.printNum(b[1]), // Index 1: balance of the budget.
this.elt('div', {}, this.elt('button', {
id: 'btnEditBudget',
class: 'btn btn-outline-primary',
onclick: `$('#modalHidden').val('${b[0]}')`,
['data-toggle']: 'modal',
['data-target']: '#divModal'
}, this.template.icon('edit', 'black')))]);
if (this.storage.readMainStorage('allocationOn')) {
let allocation = this.storage.readMainStorage('allocation');
rows.forEach((row, index) => row.push(allocation[index][1] + '\u0025')); // \u0025 = %
}
rows.unshift(headings);
$(id).html(this.template.table(rows));
let overallBalance = budgets.map(b => b[1]).reduce((prev, curr) => prev + curr, 0);
let overallLabel = `${this.textData['overallBalance']}: ${this.printNum(overallBalance)}`;
$(id).append(this.elt('center', {}, overallLabel));
}
/**
* Displays all recurring transactions in a simple overview.
*
* @param {string} id The id of the dom element which contains the
* recurring transactions display.
*/
displayRecurrTrans(id) {
let tableRows = [[
this.textData['name'], this.textData['amount'], this.textData['type'],
this.textData['budget'], this.textData['category'], this.textData['nextExecution'],
this.textData['interval'], this.textData['endDate'], this.textData['edit']
]];
this.storage.readMainStorage('recurring').sort((a, b) => a.name < b.name ? -1 : 1).forEach(t => {
let allocOn = t.allocationOn;
tableRows.push([
t.name, this.printNum(t.amount), this.textData[t.type], allocOn ? '\u2013' : t.budget,
t.category, timestampToString(t.nextDate), this.textData['intervalNames'][t.interval],
t.endDate > 0 ? timestampToString(t.endDate) : '\u2013',
this.elt('button', {
id: 'btnEditRecTrans',
class: 'btn btn-outline-primary',
onclick: `$('#modalHidden').val('${t.startDate}')`,
['data-toggle']: 'modal',
['data-target']: '#divModal',
}, this.template.icon('edit', 'black')),
]);
});
if (tableRows.length > 1) {
$(id).html(this.template.table(tableRows));
} else {
$(id).html(this.textData['noRecurrTrans']);
}
}
/**
* Displays the current (= current month) surplus for each budget.
*
* @param {string} id The id of the dom element in which the content should appear.
*/
displayBalances(id) {
$(id).html('');
let totalSum = 0;
for (let budget of this.storage.readMainStorage('budgets')) {
let budgetName = budget[0];
let earnings = this.dataHandle.getMonthlySum(budgetName, 'earning');
let spendings = this.dataHandle.getMonthlySum(budgetName, 'spending');
$(id).append(this.elt('h4', {class: 'mt-3 mb-2'}, this.template.icon(
'creditcard', 'blue'
), ` ${budgetName}`));
let balance = earnings - spendings;
let percentage = balance > 0 ? ((earnings - spendings) / earnings) * 100 : 100;
let color = balance > 0 ? 'green' : (balance < 0 ? 'red' : 'gray');
$(id).append(this.template.progress(percentage, color, this.printNum(balance)));
totalSum += parseFloat(balance);
}
let totalSumLabel = `${this.textData['totalSum']}: ${this.printNum(totalSum)}`;
$(id).append(this.elt('center', {class: 'mt-3 mb-2'}, totalSumLabel));
}
/**
* Displays recent transactions, if existing.
*
* @param {string} id The id of the dom element in which the content should appear.
* @param {string} type The type of transactions we want to display
* (can be either earning or spending).
*/
displayRecentTransactions(id, type) {
let limit = 10; // Maximum number of entries to be displayed.
$(id).html('');
let data = this.dataHandle.getRecentTrans(limit, type);
if (data.length) {
$(id).append(this.template.table(data.map(d => [
this.elt('div', {}, d.type === 'earning' ?
this.template.icon('cashregister', 'green') : this.template.icon('shoppingbag', 'red'),
` ${d.name}`),
this.printNum(d.amount),
timestampToString(d.date)
]))); // Displays the table.
}
else {
// Display a message that no earnings/spendings exist.
$(id).append(`${this.textData['no' + this.capFirstLetter(type)]}`);
}
}
/**
* Adds a new value to the array of possible autocomplete options, if it is not included yet.
*
* @param {string} field The field to which a new value should be added.
* @param {string} newValue The new value to add.
*/
addToAutocomplete(field, newValue) {
let arr = this.storage.readMainStorage(field);
if (!arr.includes(newValue) && newValue !== '') {
arr.push(newValue);
}
this.storage.writeMainStorage(field, arr);
}
}
module.exports = IndexView;