Browse Source

Create page to view allowances.

Lee Morgan 11 months ago
parent
commit
2174886647

+ 13 - 0
src/views/js/data/Account.js

@@ -43,6 +43,10 @@ export default class Account{
         return this._bills;
     }
 
+    get allowances(){
+        return this._allowances;
+    }
+
     get isPopulated(){
         return this._populated;
     }
@@ -51,6 +55,15 @@ export default class Account{
         if(typeof v === "boolean") this._populated = v;
     }
 
+    getIncomeSum(raw = false){
+        let total = 0;
+        for(let i = 0; i < this._income.length; i++){
+            if(this._income[i].active) total += this._income[i].amountRaw;
+        }
+        if(raw) return total;
+        return Format.centsToDollars(total);
+    }
+
     getCategory(category, categoryId){
         if(category === "discretionary") return {name: "Discretionary"};
 

+ 12 - 0
src/views/js/data/Allowance.js

@@ -1,3 +1,5 @@
+import Format from "../Format.js";
+
 export default class Allowance{
     constructor(id, name, amount, isPercent, active){
         this._id = id;
@@ -23,6 +25,16 @@ export default class Allowance{
         return this._active;
     }
 
+    amountInDollars(income){
+        if(this._isPercent) return Format.centsToDollars(income * (this._amount / 100));
+        return Format.centsToDollars(this._amount);
+    }
+
+    rawAmount(){
+        if(this._isPercent) return this._amount;
+        return Format.centsToDollars(this._amount);
+    }
+
     static create(name, amount, isPercent){
         return new Allowance(
             crypto.randomUUID(),

+ 4 - 0
src/views/js/data/Income.js

@@ -24,6 +24,10 @@ export default class Income{
         return Format.centsToDollars(this._amount);
     }
 
+    get amountRaw(){
+        return this._amount;
+    }
+
     set amount(v){
         if(typeof v === String) v = Number(v);
         this._amount = Format.dollarsToCents(v);

+ 2 - 1
src/views/js/index.js

@@ -18,6 +18,7 @@ import ViewIncome from "./pages/ViewIncome.js";
 import EditIncome from "./pages/EditIncome.js";
 import ViewBills from "./pages/ViewBills.js";
 import EditBill from "./pages/EditBill.js";
+import ViewAllowances from "./pages/ViewAllowances.js";
 
 const pages = document.querySelector(".page");
 let currentPage;
@@ -26,7 +27,6 @@ window.changePage = (page, data)=>{
     console.time("change page");
     currentPage.close();
 
-    console.log(page);
     switch(page){
         case "login": currentPage = new Login(); break;
         case "register": currentPage = new Register(); break;
@@ -45,6 +45,7 @@ window.changePage = (page, data)=>{
         case "editIncome": currentPage = new EditIncome(data); break;
         case "viewBills": currentPage = new ViewBills(); break;
         case "editBill": currentPage = new EditBill(data); break;
+        case "viewAllowances": currentPage = new ViewAllowances(data); break;
     }
     console.timeEnd("change page");
 }

+ 101 - 0
src/views/js/pages/ViewAllowances.js

@@ -0,0 +1,101 @@
+import Page from "./Page.js";
+import Elem from "../Elem.js";
+import Format from "../Format.js";
+
+export default class ViewAllowances extends Page{
+    constructor(){
+        super("ViewAllowances", ["home", "back-viewMenu", "logout"]);
+
+        this.render(false);
+    }
+
+    generateColor(spent, amount){
+        if(amount <= 0) return "hsl(0, 100%, 50%)";
+
+        const percent = Math.min(spent / amount, 1); 
+        let hue;
+        if(percent < 0.5){
+            hue = percent / 0.5 * 45;
+        }else{
+            hue = 45 + (percent - 0.5) / 0.5 * (120 -45);
+        }
+
+        const saturation = 65 - percent * 15;
+        const lightness = 28 + (1 - Math.abs(percent - 0.5) * 2) * 10;
+
+        return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
+    }
+
+    toggleActive(){
+        const showArchived = this.container.querySelector(".archiveCheckbox").checked;
+        this.renderItems(showArchived);
+    }
+
+    renderItems(showArchived){
+        const container = this.container.querySelector(".categoryContainer");
+        while(container.children.length > 0){
+            container.removeChild(container.lastChild);
+        }
+
+        const allowances = user.account.allowances;
+        const income = user.account.getIncomeSum(true);
+        for(let i = 0; i < allowances.length; i++){
+            if(!showArchived && !allowances[i].active) continue;
+            const spent = user.account.categorySpent(allowances[i]);
+            const spentAsCurrency = Format.currency(spent);
+            const amount = allowances[i].amountInDollars(income);
+            const amountAsCurrency = Format.currency(amount);
+
+            new Elem("button")
+                .addClass("viewCategoryItem")
+                .onclick(()=>{changePage("editAllowance")})
+                .append(new Elem("p")
+                    .text(allowances[i].name)
+                    .addClass(allowances[i].active ? "none" : "strike")
+                )
+                .append(new Elem("p")
+                    .addClass("categoryItemSpent")
+                    .append(new Elem("span")
+                        .text(spentAsCurrency)
+                        .addStyle("color", this.generateColor(spent, amount))
+                    )
+                    .append(new Elem("span")
+                        .text(" / ")
+                    )
+                    .append(new Elem("span")
+                        .text(amountAsCurrency)
+                        .addStyle("color", "hsl(120, 50%, 28%)")
+                    )
+                )
+                .appendTo(container);
+        }
+    }
+
+    render(showArchived){
+        new Elem("h1")
+            .text(`${user.account.name} Allowances`)
+            .appendTo(this.container);
+
+        new Elem("label")
+            .addClass("switch")
+            .append(new Elem("p")
+                .text("Show Archived")
+            )
+            .append(new Elem("input")
+                .type("checkbox")
+                .addClass("archiveCheckbox")
+                .checked(false)
+                .onchange(this.toggleActive.bind(this))
+            )
+            .append(new Elem("span")
+                .addClass("slider")
+            )
+            .appendTo(this.container);
+
+        new Elem("div")
+            .addClass("categoryContainer")
+            .appendTo(this.container);
+
+        this.renderItems(showArchived);
+    }
+}

+ 6 - 0
src/views/js/pages/ViewMenu.js

@@ -16,6 +16,12 @@ export default class ViewMenu extends Page{
             .focus()
             .appendTo(this.container);
 
+        new Elem("button")
+            .text("Allowances")
+            .addClass("button")
+            .onclick(()=>{changePage("viewAllowances")})
+            .appendTo(this.container);
+
         new Elem("button")
             .text("Bills")
             .addClass("button")