Skip to content

Commit df3bba0

Browse files
committed
add Budget Tracker
1 parent 1670231 commit df3bba0

File tree

7 files changed

+340
-0
lines changed

7 files changed

+340
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Welcome to the Mini Projects Showcase! This repository contains a collection of
66

77
- Accordion
88
- Age Calculator
9+
- Budget Tracker
910
- Calculator
1011
- Color Flipper
1112
- Color Palette Generator

budget-tracker/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Budget Tracker
2+
3+
A simple Budget Tracker application that allows users to set a budget, track their expenses, and calculate the remaining balance. Users can add, edit, and delete expense items, with real-time updates on the budget, expenses, and balance.
4+
5+
## Features
6+
7+
- Set a total budget
8+
- Add, edit, and delete expense items
9+
- View the total budget, total expenses, and remaining balance in real-time
10+
11+
## Technologies Used
12+
13+
- HTML for the structure
14+
- CSS (with Bootstrap) for styling
15+
- JavaScript for functionality
16+
17+
## File Structure
18+
19+
```bash
20+
/budget-tracker
21+
├── index.html # Main HTML file
22+
├── style.css # Custom CSS styles (if applicable)
23+
├── app.js # JavaScript functionality
24+
├── README.md # Project documentation (this file)
25+
```
26+
27+
## Screenshot
28+
29+
![Screenshot of Budget Tracker](./budget-tracker-ui.png)

budget-tracker/app.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
const budgetInput = document.querySelector(".budget-box input"),
2+
setBudgetBtn = document.querySelector(".budget-box button"),
3+
totalBudgetResult = document.getElementById("total-budget"),
4+
totalExpenseResult = document.getElementById("total-expense"),
5+
totalBalanceResult = document.getElementById("total-balance"),
6+
productTitleInput = document.querySelector(".expense-box").children[1],
7+
productCostInput = document.querySelector(".expense-box").children[2],
8+
addProductBtn = document.querySelector(".expense-box button"),
9+
expenseListWrapper = document.querySelector(".expense-list-wrapper");
10+
11+
let totalBudgetAmount = 0,
12+
totalExpenseAmount = 0,
13+
totalBalanceAmount = 0;
14+
15+
// Update HTML content with the current values
16+
const updateHTML = () => {
17+
totalBudgetResult.textContent = totalBudgetAmount;
18+
totalExpenseResult.textContent = totalExpenseAmount;
19+
totalBalanceResult.textContent = totalBalanceAmount;
20+
};
21+
22+
// Set the budget amount and update the results
23+
const setBudget = () => {
24+
let budgetAmount = parseInt(budgetInput.value);
25+
26+
if (budgetAmount <= 0 || isNaN(budgetAmount))
27+
return alert("Enter a valid positive budget value");
28+
29+
totalBudgetAmount += budgetAmount;
30+
totalBalanceAmount += budgetAmount;
31+
32+
updateHTML();
33+
budgetInput.value = "";
34+
};
35+
36+
// Render the product in the expense list
37+
const renderProduct = (title, cost) => {
38+
const listBox = `
39+
<div
40+
class="d-flex align-items-center justify-content-between px-3 py-2 mb-3 list-box"
41+
>
42+
<input type="text" value="${title}" class="fw-medium" readonly />
43+
<input type="number" value="${cost}" readonly />
44+
<div class="d-flex align-items-center text-primary gap-2">
45+
<i class="ri-edit-box-line"></i>
46+
<i class="ri-delete-back-line"></i>
47+
</div>
48+
</div>`;
49+
50+
expenseListWrapper.insertAdjacentHTML("beforeend", listBox);
51+
};
52+
53+
// Add product to the expense list and update amounts
54+
const addProduct = () => {
55+
let productTitle = productTitleInput.value,
56+
productCost = parseInt(productCostInput.value);
57+
58+
if (!productTitle) return alert("Enter product title");
59+
if (productCost <= 0 || isNaN(productCost))
60+
return alert("Enter a valid positive product cost");
61+
if (productCost > totalBalanceAmount) return alert("Not enough balance!");
62+
63+
renderProduct(productTitle, productCost);
64+
65+
totalExpenseAmount += productCost;
66+
totalBalanceAmount -= productCost;
67+
68+
updateHTML();
69+
70+
productTitleInput.value = "";
71+
productCostInput.value = "";
72+
};
73+
74+
// Handle edit and delete actions for expenses
75+
expenseListWrapper.addEventListener("click", (e) => {
76+
const editBtn = e.target.closest(".ri-edit-box-line");
77+
const deleteBtn = e.target.closest(".ri-delete-back-line");
78+
const currentListBox = e.target.closest(".list-box");
79+
const currentTitle = currentListBox?.querySelector("input[type='text']");
80+
const currentCost = currentListBox?.querySelector("input[type='number']");
81+
82+
if (editBtn) {
83+
if (!currentTitle.value || !currentCost.value)
84+
return alert("Value can't be empty!");
85+
86+
// Toggle editable state and save changes
87+
currentTitle.toggleAttribute("readonly");
88+
currentCost.toggleAttribute("readonly");
89+
currentTitle.classList.toggle("editable");
90+
currentCost.classList.toggle("editable");
91+
currentTitle.setAttribute("value", currentTitle.value);
92+
currentCost.setAttribute("value", currentCost.value);
93+
e.target.classList.toggle("ri-save-line");
94+
95+
// Recalculate total expenses and balance
96+
totalExpenseAmount = [
97+
...expenseListWrapper.querySelectorAll(".list-box"),
98+
].reduce(
99+
(total, box) =>
100+
total + parseInt(box.querySelector("input[type='number']").value),
101+
0
102+
);
103+
totalBalanceAmount = totalBudgetAmount - totalExpenseAmount;
104+
105+
updateHTML();
106+
}
107+
108+
if (deleteBtn) {
109+
// Remove product and adjust total values
110+
currentListBox.remove();
111+
totalExpenseAmount -= parseInt(currentCost.value);
112+
totalBalanceAmount += parseInt(currentCost.value);
113+
114+
updateHTML();
115+
}
116+
});
117+
118+
// Attach event listeners to buttons
119+
setBudgetBtn.addEventListener("click", setBudget);
120+
addProductBtn.addEventListener("click", addProduct);
415 KB
Loading

budget-tracker/index.html

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Budget Tracker</title>
7+
<link
8+
href="https://cdn.jsdelivr.net/npm/remixicon@4.5.0/fonts/remixicon.css"
9+
rel="stylesheet"
10+
/>
11+
<link
12+
rel="stylesheet"
13+
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
14+
/>
15+
<link rel="stylesheet" href="style.css" />
16+
</head>
17+
<body>
18+
<div class="container">
19+
<div class="row justify-content-center">
20+
<div class="col-11 col-sm-12 d-flex flex-column gap-4 py-4">
21+
<!-- Input Section -->
22+
<section
23+
class="d-flex flex-column flex-md-row justify-content-md-between gap-4"
24+
>
25+
<!-- Budget Box -->
26+
<div
27+
class="budget-box bg-white px-3 py-4 rounded-3 d-flex flex-column gap-3"
28+
>
29+
<h5>Budget</h5>
30+
<input
31+
type="number"
32+
class="form-control"
33+
placeholder="Enter total amount"
34+
/>
35+
<button class="btn btn-outline-primary">Set Budget</button>
36+
</div>
37+
38+
<!-- Expense Box -->
39+
<div
40+
class="expense-box bg-white px-3 py-4 rounded-3 d-flex flex-column gap-3"
41+
>
42+
<h5>Expenses</h5>
43+
<input
44+
type="text"
45+
class="form-control"
46+
placeholder="Enter title of product"
47+
/>
48+
<input
49+
type="number"
50+
class="form-control"
51+
placeholder="Enter cost of product"
52+
/>
53+
<button class="btn btn-outline-primary">Add Product</button>
54+
</div>
55+
</section>
56+
57+
<!-- Result Section -->
58+
<section
59+
class="result-box bg-primary rounded-3 p-3 p-md-4 text-white d-flex align-items-center justify-content-between text-center"
60+
>
61+
<div class="d-flex flex-column gap-2">
62+
<p class="fw-medium">Total Budget</p>
63+
<p id="total-budget">0</p>
64+
</div>
65+
<div class="d-flex flex-column gap-2">
66+
<p class="fw-medium">Expenses</p>
67+
<p id="total-expense">0</p>
68+
</div>
69+
<div class="d-flex flex-column gap-2">
70+
<p class="fw-medium">Balance</p>
71+
<p id="total-balance">0</p>
72+
</div>
73+
</section>
74+
75+
<!-- Expense List Section -->
76+
<section
77+
class="bg-white rounded-3 px-4 pt-3 d-flex flex-column gap-3 expense-list-section"
78+
>
79+
<h5>Expense List</h5>
80+
<div class="expense-list-wrapper overflow-x-auto"></div>
81+
</section>
82+
</div>
83+
</div>
84+
</div>
85+
</body>
86+
<script src="app.js"></script>
87+
</html>

budget-tracker/style.css

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap");
2+
3+
* {
4+
margin: 0;
5+
padding: 0;
6+
box-sizing: border-box;
7+
}
8+
9+
p,
10+
h1,
11+
h2,
12+
h3,
13+
h4,
14+
h5,
15+
h6 {
16+
margin: 0;
17+
}
18+
19+
html,
20+
body {
21+
width: 100%;
22+
height: 100%;
23+
}
24+
25+
body {
26+
background-color: azure;
27+
font-family: "Poppins", serif;
28+
}
29+
30+
.form-control:focus {
31+
box-shadow: none;
32+
}
33+
34+
.budget-box,
35+
.expense-box {
36+
width: 50%;
37+
}
38+
39+
.budget-box,
40+
.expense-box,
41+
.expense-list-section {
42+
box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
43+
}
44+
45+
.result-box,
46+
.list-box {
47+
font-size: 17px;
48+
}
49+
50+
.expense-list-wrapper {
51+
display: flex;
52+
flex-direction: column;
53+
}
54+
55+
.list-box {
56+
position: relative;
57+
}
58+
59+
.list-box::before {
60+
position: absolute;
61+
content: "";
62+
left: 0;
63+
top: 0;
64+
width: 6px;
65+
height: 100%;
66+
background-color: #0d6efd;
67+
}
68+
69+
.list-box input {
70+
border: unset;
71+
outline: unset;
72+
}
73+
74+
.list-box input:first-child {
75+
text-transform: capitalize;
76+
}
77+
78+
.list-box input.editable {
79+
border: 1px solid gray;
80+
border-radius: 5px;
81+
padding: 3px 6px;
82+
}
83+
84+
.list-box i {
85+
font-size: 20px;
86+
cursor: pointer;
87+
}
88+
89+
@media only screen and (max-width: 768px) {
90+
.budget-box,
91+
.expense-box {
92+
width: 100%;
93+
}
94+
95+
.result-box,
96+
.list-box {
97+
font-size: 16px;
98+
}
99+
}

data.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,8 @@ const projects = [
119119
name: "Flashcard App",
120120
link: "flashcard-app/index.html",
121121
},
122+
{
123+
name: "Budget Tracker",
124+
link: "budget-tracker/index.html",
125+
},
122126
];

0 commit comments

Comments
 (0)