var budgetController = (function () {
let Expense = function(id, description, value) {
this.id = id;
this.description = description;
this.value = value;
this.percentage = -1;
}
Expense.prototype.calcPercentage = function(totalIncome) {
if (totalIncome > 0) this.percentage = (this.value / totalIncome) * 100
else this.percentage = -1;
}
Expense.prototype.getPercentage = function() {
return this.percentage;
}
let Income = function(id, description, value) {
this.id = id;
this.description = description;
this.value = value;
}
let calculateTotal = function(type) {
let dataArr = data.allItems[type];
let total = 0;
for (let i = 0; i < dataArr.length; i++) {
total = total + dataArr[i].value;
}
data.total[type] = total;
return total;
}
var data = {
allItems: {
exp: [],
inc: [],
},
total: {
exp: 0,
inc: 0
},
budget: 0,
totalPercentage: 0
}
return {
addItem: function(type, desc, value) {
let lastIndex = data.allItems[type].length - 1;
let arr = data.allItems[type];
let ID = (lastIndex < 0) ? 0 : arr[lastIndex].id + 1
var newItem = (type==='exp') ? new Expense(ID, desc, value) : new Income(ID, desc, value);
data.allItems[type].push(newItem);
return newItem;
},
deleteItem: function(type, ayeDee) {
console.log(`budgetController - deleteItem: type ${type}, id ${ayeDee}`);
let dataArr = data.allItems[type];
let indexToDelete = -1;
for ( let i = 0; i < dataArr.length; i++) {
let item = dataArr[i];
if (item.id === ayeDee) {
indexToDelete = i;
break;
}
}
if (indexToDelete !== -1) {
dataArr.splice(indexToDelete, 1);
} else {
console.log(`item with id ${ayeDee} not foud`)
}
},
calculateBudget: function() {
calculateTotal('exp');
calculateTotal('inc');
data.budget = data.total.inc - data.total.exp;
if (data.total.inc > 0 && data.total.exp > 0) {
data.totalPercentage = (data.total.exp / data.total.inc) * 100;
} else if (data.total.exp > 0 && data.total.inc == 0) {
data.totalPercentage = 100;
} else if (data.total.exp == 0 && data.total.inc > 0) {
data.totalPercentage = 0;
}
},
calculatePercentages: function() {
let numOfExpenses = data.allItems.exp.length;
let arrOfExpenses = data.allItems.exp;
for (let i = 0; i < numOfExpenses; i++) {
let expense = arrOfExpenses[i];
if (expense instanceof Expense &&
typeof expense.calcPercentage === 'function') {
expense.calcPercentage(data.total.inc);
}
}
},
getPercentages: function() {
var allPerc = data.allItems.exp.map( function(expObj) {
return expObj.getPercentage();
});
return allPerc;
},
getBudget: function() {
return {
budget: data.budget,
totalIncome: data.total.inc,
totalExpense: data.total.exp,
totalPercentage: data.totalPercentage
}
}
}
})();
var UIController = (function() {
// private
var DOMStrings = {
INPUT_TYPE: '.add__type',
INPUT_DESCRIPTION: '.add__description',
INPUT_VALUE: '.add__value',
INPUT_BUTTON: '.add__btn',
INCOME_CONTAINER: '.income__list',
EXPENSE_CONTAINER: '.expenses__list',
BUDGET_LABEL: '.budget__value',
INCOME_LABEL: '.budget__income--value',
EXPENSES_LABEL: '.budget__expenses--value',
PERCENTAGE_LABEL: '.budget__expenses--percentage',
CONTAINER: '.container',
ITEM_PERCENTAGE_LABEL: '.item__percentage',
DATE_LABEL: '.budget__title--month',
}
var monthStrings = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
return {
getInput: function() {
return {
// value come from <option value='XXXXXXX'>....</option>
// user selects as expense/income
selectedType: document.querySelector(DOMStrings.INPUT_TYPE).value,
// description of the expense/income
description: document.querySelector(DOMStrings.INPUT_DESCRIPTION).value,
// the value of the expense/income
value: parseFloat(document.querySelector(DOMStrings.INPUT_VALUE).value),
}
},
displayAllPercentage: function(percentages) {
let fields = document.querySelectorAll(DOMStrings.ITEM_PERCENTAGE_LABEL);
console.log(fields)
// declaration of var, takes on function expression
var nodeListForEach = function(list, callback) {
for( let i = 0; i < list.length; i++) {
callback(list[i], i);
}
};
// execution
nodeListForEach(fields, function(current, index){
if (percentages[index] > 0) current.textContent = percentages[index] + '%';
else current.textContent = '---';
});
},
displayMonth: function() {
let d = new Date();
year = d.getFullYear();
month = d.getMonth();
document.querySelector(DOMStrings.DATE_LABEL).textContent = monthStrings[month-1] + ', ' + year;
},
// expose private DOMStrings literal object to public
getDOMStrings: function() {
return DOMStrings;
},
addListItem: function(obj, type) {
// create HTML string with placeholder text
var html, element;
if (type === 'inc') {
element = DOMStrings.INCOME_CONTAINER;
html = `<div class="item clearfix" id="inc-${obj.id}">
<div class="item__description">${obj.description}</div>
<div class="right clearfix">
<div class="item__value">+ ${obj.value}</div>
<div class="item__delete">
<button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div>
</div>
</div>`;
} else if (type==='exp') {
element = DOMStrings.EXPENSE_CONTAINER;
html = `<div class="item clearfix" id="exp-${obj.id}">
<div class="item__description">${obj.description}</div>
<div class="right clearfix">
<div class="item__value">- ${obj.value}</div>
<div class="item__percentage"></div>
<div class="item__delete">
<button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div>
</div>
</div>`;
} else {
}
// insert html into dom
document.querySelector(element).insertAdjacentHTML('beforeend', html)
},
deleteItemElement: function(selector) {
console.log(`deleting item with id ${selector}`)
let ele = document.querySelector('#'+selector);
console.log(ele)
if (ele) ele.parentNode.removeChild(ele);
},
clearField: function() {
document.querySelector(DOMStrings.INPUT_DESCRIPTION).value = '';
document.querySelector(DOMStrings.INPUT_VALUE).value = '';
document.querySelector(DOMStrings.INPUT_DESCRIPTION).focus();
},
displayBudget: function(data) {
document.querySelector(DOMStrings.BUDGET_LABEL).textContent = data.budget;
document.querySelector(DOMStrings.INCOME_LABEL).textContent = data.totalIncome;
document.querySelector(DOMStrings.EXPENSES_LABEL).textContent = data.totalExpense;
let formattedPercentage = data.totalPercentage > 0 ? data.totalPercentage.toFixed(2) : 0;
console.log(formattedPercentage);
document.querySelector(DOMStrings.PERCENTAGE_LABEL).textContent = formattedPercentage + ' %';
}
}
})();
var controller = (function(budgetCtrl, UICtrl) {
var setupEventListener = function() {
var DOM = UICtrl.getDOMStrings();
document.querySelector(DOM.INPUT_BUTTON).addEventListener('click', ctrlAddItem);
document.addEventListener('keypress', function(event) {
if (event.keyCode === 13 || event.which === 13) { // return key
ctrlAddItem();
}
})
document.querySelector(DOM.CONTAINER).addEventListener('click', ctrlDeleteItem);
}
function updateBudget() {
budgetCtrl.calculateBudget();
let budget = budgetCtrl.getBudget();
UICtrl.displayBudget(budget)
}
function ctrlDeleteItem(event) {
console.log('--- an event came from ---');
// its ok for us to hardcode the finding of the id because when we add
// an expense or income, our html is hardcoded.
// This ensures that clicking on an x button will get us the id for that particular
// list item html
let itemID = event.target.parentNode.parentNode.parentNode.parentNode.id;
if (itemID) {
let arr = itemID.split('-');
let type = arr[0];
let ayeDee = arr[1];
// delete ite from our data struvture
budgetCtrl.deleteItem(type, parseFloat(ayeDee));
// delete item from UI
UICtrl.deleteItemElement(itemID);
// update and show new budget
updateBudget();
}
}
function updatePercentages() {
// 1) calculate percentages
budgetCtrl.calculatePercentages();
// 2) read from budget controller
let arrOfPercentages = budgetCtrl.getPercentages();
// 3 ) update user interface
UICtrl.displayAllPercentage(arrOfPercentages);
}
function ctrlAddItem() {
// get input field
let input = UICtrl.getInput();
if (input.description !== "" && !isNaN(input.value) && input.value > 0 ) {
// add item to budget controller
var newItem = budgetCtrl.addItem(input.selectedType,
input.description,
input.value);
// add item to UI
UICtrl.addListItem(newItem, input.selectedType);
UICtrl.clearField();
updateBudget();
updatePercentages();
}
}
return {
init: function() {
console.log('Application has started... √');
setupEventListener();
UICtrl.displayMonth();
}
}
})(budgetController, UIController);
controller.init();