diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2a1f079..8adceba 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -1,7 +1,7 @@ name: Test School Vanilla JS on: - pull_request_target:: + pull_request_target: types: [opened, synchronize, reopened] branches: ["main", "master"] diff --git a/package-lock.json b/package-lock.json index f381c35..14682d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "bug-hunt", + "name": "buget-tracker", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "bug-hunt", + "name": "buget-tracker", "version": "1.0.0", "license": "ISC", "dependencies": { diff --git a/src/index.html b/src/index.html index 5d0f212..fcbd648 100644 --- a/src/index.html +++ b/src/index.html @@ -3,7 +3,7 @@ - Buget Tracker + Budget Tracker @@ -143,6 +143,7 @@

Manage Categories

+
@@ -187,5 +188,7 @@

Savings Goals

+ + \ No newline at end of file diff --git a/src/script.js b/src/script.js index 7ff5275..5baed0c 100644 --- a/src/script.js +++ b/src/script.js @@ -56,21 +56,73 @@ let transactions = getTransactionsFromStorage(); function addTransaction(e, descriptionEl, amountEl, categoryEl, dateEl) { e.preventDefault(); - const amount = parseFloat(amountEl.value); - - const description = descriptionEl.value; + // Enhanced input validation + const description = descriptionEl.value.trim(); + const amountStr = amountEl.value.trim(); const category = categoryEl.value; const date = dateEl.value; + // Validate all inputs thoroughly + if (!description) { + alert("Please enter a description for the transaction."); + descriptionEl.focus(); + return; + } + + if (!amountStr) { + alert("Please enter an amount for the transaction."); + amountEl.focus(); + return; + } + + const amount = parseFloat(amountStr); + if (isNaN(amount)) { + alert("Please enter a valid number for the amount."); + amountEl.focus(); + return; + } + + if (amount === 0) { + alert("Amount cannot be zero. Please enter a non-zero value."); + amountEl.focus(); + return; + } + + if (!category) { + alert("Please select a category for the transaction."); + categoryEl.focus(); + return; + } + + if (!date) { + alert("Please select a date for the transaction."); + dateEl.focus(); + return; + } + + // Create transaction object const newTransaction = { + id: generateID(), description, amount, category, date, }; - transaction.push(newTransaction); + // Add to transactions array + transactions.push(newTransaction); updateLocalStorage(); + + // Reset form with improved user experience + descriptionEl.value = ""; + amountEl.value = ""; + categoryEl.value = "Other"; + dateEl.valueAsDate = new Date(); // Reset to today's date instead of clearing + + // Focus on the description field for the next entry + descriptionEl.focus(); + + console.log("Transaction added:", newTransaction); } // Generate unique ID @@ -94,21 +146,23 @@ function removeTransaction(id) { function updateValues(balanceEl, incomeEl, expenseEl) { const amounts = transactions.map((transaction) => transaction.amount); - const total = amounts.reduce((acc, amount) => { - return (acc = amount); - }, 0); - + // Calculate income (sum of all positive amounts) const income = amounts .filter((amount) => amount > 0) .reduce((acc, amount) => acc + amount, 0); + // Calculate expenses (sum of all negative amounts as a positive number) const expense = amounts .filter((amount) => amount < 0) - .reduce((acc, amount) => acc - amount, 0); + .reduce((acc, amount) => acc + Math.abs(amount), 0); + + // Calculate balance as income minus expenses + const balance = income - expense; - balanceEl.textContent = `Rs ${total}`; - incomeEl.textContent = `+Rs ${income}`; - expenseEl.textContent = `-Rs ${Math.abs(expense)}`; + // Update UI elements with formatted values + balanceEl.textContent = `Rs ${balance.toFixed(2)}`; + incomeEl.textContent = `+Rs ${income.toFixed(2)}`; + expenseEl.textContent = `-Rs ${expense.toFixed(2)}`; } // Add transactions to DOM @@ -117,7 +171,8 @@ function addTransactionDOM(transaction, transactionListEl) { const item = document.createElement("li"); - item.className = transaction.category === "income" ? "expense" : "income"; + // Fix incorrect class assignment - base it on amount instead of category name + item.className = transaction.amount < 0 ? "expense" : "income"; const detailsDiv = document.createElement("div"); detailsDiv.className = "details"; @@ -275,14 +330,16 @@ function generateReport() { .filter((t) => t.amount > 0) .reduce((acc, t) => acc + t.amount, 0); + // Fix: Filter for negative amounts for expenses const totalExpense = transactions - .filter((t) => t.amount > 0) - .reduce((acc, t) => acc + t.amount, 0); + .filter((t) => t.amount < 0) + .reduce((acc, t) => acc + Math.abs(t.amount), 0); const balance = totalIncome - totalExpense; + // Consistent decimal formatting for all monetary values reportText += `Total Income: Rs ${totalIncome.toFixed(2)}\n`; - reportText += `Total Expense: Rs ${Math.abs(totalExpense).toFixed(2)}\n`; + reportText += `Total Expense: Rs ${totalExpense.toFixed(2)}\n`; reportText += `Balance: Rs ${balance.toFixed(2)}\n\n`; // Category breakdown @@ -290,12 +347,21 @@ function generateReport() { const categorySummary = {}; + // Initialize all categories with zero + transactions.forEach((t) => { + if (t.amount < 0 && !categorySummary[t.category]) { + categorySummary[t.category] = 0; + } + }); + + // Sum expenses by category transactions.forEach((t) => { if (t.amount < 0) { categorySummary[t.category] += Math.abs(t.amount); } }); + // Format and display each category for (const category in categorySummary) { reportText += `${category}: Rs ${categorySummary[category].toFixed(2)}\n`; } @@ -403,8 +469,8 @@ function deleteCategory(categoryName) { // Update transactions with this category to "Other" or first available category const defaultCategory = "Other"; - const transactions = getTransactionsFromStorage(); - + + // Use the global transactions variable instead of redeclaring it transactions.forEach((transaction) => { if (transaction.category === categoryName) { transaction.category = defaultCategory; @@ -431,18 +497,15 @@ function updateCategoryDropdowns(categoryDropdowns) { const currentValue = dropdown.value; dropdown.innerHTML = ""; - // Add all categories + // Add all categories without unnecessary formatting categories.forEach((category) => { - dropdown.insertAdjacentHTML( - "beforeend", - `` - ); + const option = document.createElement("option"); + option.value = category; + option.textContent = category; + dropdown.appendChild(option); }); - if ( - currentValue && - dropdown.querySelector(`option[value="${currentValue}"]`) - ) { + if (currentValue && dropdown.querySelector(`option[value="${currentValue}"]`)) { dropdown.value = currentValue; } }); diff --git a/src/styles.css b/src/styles.css index 520c53a..6d3ff56 100644 --- a/src/styles.css +++ b/src/styles.css @@ -115,11 +115,19 @@ header { width: 95%; max-width: 1200px; margin: 0 auto; - /* Bug #23: display should flex */ + display: flex; /* Adding display flex to properly structure the layout */ flex-wrap: wrap; gap: 20px; } +/* Enhancing UI structure by defining a grid layout for the main container */ +.main-container { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: auto auto; + gap: 20px; +} + .dashboard { flex: 1; min-width: 300px; @@ -287,8 +295,8 @@ select { .tab-content.active { display: block; - /* Bug #24: overflow-y should be set to auto */ height: 370px; + overflow-y: auto; } /* Transaction List */