Skip to content

Commit 207b827

Browse files
committed
add income expense tracker
1 parent f58b721 commit 207b827

File tree

7 files changed

+317
-0
lines changed

7 files changed

+317
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Welcome to the Mini Projects Showcase! This repository contains a collection of
1515
- Dynamic Menu
1616
- Gradient Generator
1717
- Image Search Engine
18+
- Income Expense Tracker
1819
- Language Translator
1920
- Navbar
2021
- Number Guessing Game

data.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,8 @@ const projects = [
111111
name: "Weather App II",
112112
link: "weather-app-II/index.html",
113113
},
114+
{
115+
name: "Income Expense Tracker",
116+
link: "income-expense-tracker/index.html",
117+
},
114118
];

income-expense-tracker/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Income-Expense-Tracker
2+
3+
This is a simple income and expense tracker web application built using vanilla JavaScript. The app allows users to add and remove transactions, track their total income and expenses, and view the current balance. The application also persists data across sessions using localStorage, ensuring that your transactions are saved even after you close the browser.
4+
5+
## Features
6+
7+
- **Track Income & Expenses**: Add transactions as either income or expenses.
8+
- **Balance Calculation**: Automatically calculates the balance based on total income and total expenses.
9+
- **Persistent Data**: Stores transactions in localStorage so that data is preserved between page refreshes.
10+
- **Transaction Removal**: Remove individual transactions and update the balance accordingly.
11+
- **Responsive Design**: The app is designed to be mobile-friendly.
12+
13+
## Technologies Used
14+
15+
- **HTML**: For the basic structure of the application.
16+
- **CSS**: For styling the app.
17+
- **JavaScript**: For adding interactivity, handling transactions, and managing localStorage.
18+
- **Bootstrap**: For quick and easy styling.

income-expense-tracker/app.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// Select DOM elements
2+
const descInput = document.querySelector("#desc");
3+
const amountInput = document.querySelector("#amount");
4+
const incomeBox = document.querySelector("#income-box");
5+
const expenseBox = document.querySelector("#expense-box");
6+
const balance = document.querySelector("#balance");
7+
const transactionDetails = document.querySelector(".transaction-details");
8+
const form = document.querySelector("form");
9+
10+
// Track total income and expense
11+
let totalIncome = 0;
12+
let totalExpense = 0;
13+
14+
// Function to load transactions from localStorage
15+
const loadTransactions = () => {
16+
const storedTransactions =
17+
JSON.parse(localStorage.getItem("transactions")) || [];
18+
19+
storedTransactions.forEach((transaction) => {
20+
if (transaction.amount > 0) {
21+
totalIncome += transaction.amount;
22+
} else {
23+
totalExpense += Math.abs(transaction.amount);
24+
}
25+
transactionDetails.insertAdjacentHTML(
26+
"beforeend",
27+
transactionBoxHandler(transaction.desc, transaction.amount)
28+
);
29+
});
30+
31+
updateAmountDisplay();
32+
updateBalance();
33+
};
34+
35+
// Update balance display
36+
const updateBalance = () => {
37+
const totalBalance = totalIncome - totalExpense;
38+
balance.textContent = totalBalance.toFixed(2);
39+
};
40+
41+
// Update income and expense displays
42+
const updateAmountDisplay = () => {
43+
incomeBox.textContent = `${totalIncome.toFixed(2)}`;
44+
expenseBox.textContent = `${totalExpense.toFixed(2)}`;
45+
};
46+
47+
// Generate HTML for a transaction box
48+
const transactionBoxHandler = (desc, amount) => {
49+
const transactionClass = amount < 0 ? "expense" : "income";
50+
return `
51+
<div class="rounded-2 py-2 px-3 d-flex align-items-center justify-content-between ${transactionClass} transaction-box">
52+
<p class="description text-capitalize">${desc}</p>
53+
<div class="d-flex align-items-center gap-2">
54+
<p class="amount">₹${amount}</p>
55+
<i class="ri-close-line remove-transaction" data-amount="${amount}"></i>
56+
</div>
57+
</div>
58+
`;
59+
};
60+
61+
// Save transactions to localStorage
62+
const saveTransactionsToLocalStorage = () => {
63+
const transactions = [];
64+
65+
// Get all transaction boxes
66+
const transactionsBoxes = document.querySelectorAll(".transaction-box");
67+
transactionsBoxes.forEach((box) => {
68+
const desc = box.querySelector(".description").textContent;
69+
const amount = parseFloat(
70+
box.querySelector(".amount").textContent.replace("₹", "")
71+
);
72+
73+
transactions.push({ desc, amount });
74+
});
75+
76+
// Save to localStorage
77+
localStorage.setItem("transactions", JSON.stringify(transactions));
78+
};
79+
80+
// Add a new transaction
81+
const addTransaction = () => {
82+
const desc = descInput.value.trim();
83+
const amount = parseFloat(amountInput.value);
84+
85+
if (!desc || isNaN(amount) || amount === 0) {
86+
return alert("Please enter a valid description and non-zero amount.");
87+
}
88+
89+
if (amount > 0) totalIncome += amount;
90+
else totalExpense += Math.abs(amount);
91+
92+
updateAmountDisplay();
93+
transactionDetails.insertAdjacentHTML(
94+
"beforeend",
95+
transactionBoxHandler(desc, amount)
96+
);
97+
updateBalance();
98+
99+
// Save the new transaction to localStorage
100+
saveTransactionsToLocalStorage();
101+
102+
// Clear inputs
103+
descInput.value = "";
104+
amountInput.value = "";
105+
106+
// Remove focus from the input fields
107+
descInput.blur();
108+
amountInput.blur();
109+
};
110+
111+
// Remove a transaction
112+
const removeTransaction = (e) => {
113+
const transactionBox = e.target.closest(".transaction-box");
114+
const amount = parseFloat(e.target.dataset.amount);
115+
116+
if (amount > 0) totalIncome -= amount;
117+
else totalExpense -= Math.abs(amount);
118+
119+
transactionBox.remove();
120+
updateAmountDisplay();
121+
updateBalance();
122+
123+
// Save updated transactions to localStorage
124+
saveTransactionsToLocalStorage();
125+
};
126+
127+
// Handle form submission
128+
form.addEventListener("submit", (e) => {
129+
e.preventDefault();
130+
addTransaction();
131+
});
132+
133+
// Event delegation for removing transactions
134+
transactionDetails.addEventListener("click", (e) => {
135+
if (e.target.classList.contains("remove-transaction")) {
136+
removeTransaction(e);
137+
}
138+
});
139+
140+
// Load transactions from localStorage when the page loads
141+
window.addEventListener("DOMContentLoaded", loadTransactions);
565 KB
Loading

income-expense-tracker/index.html

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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>Income & Expense Tracker</title>
7+
<link
8+
href="https://cdn.jsdelivr.net/npm/remixicon@4.3.0/fonts/remixicon.css"
9+
rel="stylesheet"
10+
/>
11+
<link
12+
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
13+
rel="stylesheet"
14+
/>
15+
<link rel="stylesheet" href="style.css" />
16+
</head>
17+
<body>
18+
<h2 class="text-center pt-4 pb-0 pb-sm-3 fw-bold">
19+
Income & Expense Tracker
20+
</h2>
21+
<div class="container p-4 p-sm-0 pb-sm-4 pb-lg-0">
22+
<div class="row justify-content-center">
23+
<div
24+
class="col border border-opacity-50 border-secondary rounded-2 p-4 d-flex flex-column flex-lg-row gap-4 shadow-lg"
25+
>
26+
<div class="d-flex flex-column gap-3">
27+
<div class="fw-medium">
28+
<h5>Your Balance</h5>
29+
<h4><span id="balance">0.00</span></h4>
30+
</div>
31+
<div class="d-flex flex-column flex-sm-row gap-3 fw-semibold">
32+
<div
33+
class="p-3 rounded-1 flex-grow-1 d-flex flex-column gap-1 income"
34+
>
35+
<p>Income</p>
36+
<p><span id="income-box">0.00</span></p>
37+
</div>
38+
<div
39+
class="p-3 rounded-1 flex-grow-1 d-flex flex-column gap-1 expense"
40+
>
41+
<p>Expense</p>
42+
<p><span id="expense-box">0.00</span></p>
43+
</div>
44+
</div>
45+
<form class="d-flex flex-column gap-3">
46+
<input id="desc" type="text" placeholder="Enter Description" />
47+
<input
48+
id="amount"
49+
type="text"
50+
placeholder="Enter Amount (+ Inc, - Exp)"
51+
/>
52+
<button type="submit" class="btn btn-secondary">
53+
Add Transaction
54+
</button>
55+
</form>
56+
</div>
57+
<div class="d-flex flex-column gap-3 fw-semibold transaction-details">
58+
<h5>Transaction Details</h5>
59+
</div>
60+
</div>
61+
</div>
62+
</div>
63+
64+
<script src="app.js"></script>
65+
</body>
66+
</html>

income-expense-tracker/style.css

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@100..900&display=swap");
2+
3+
* {
4+
margin: 0;
5+
padding: 0;
6+
box-sizing: border-box;
7+
font-family: "Montserrat", sans-serif;
8+
scroll-behavior: smooth;
9+
}
10+
11+
html,
12+
body {
13+
width: 100%;
14+
height: 100%;
15+
}
16+
17+
body {
18+
background-color: #222224;
19+
color: whitesmoke;
20+
}
21+
22+
p {
23+
margin: 0;
24+
}
25+
26+
input {
27+
width: 100%;
28+
padding: 5px 10px;
29+
background: transparent;
30+
border: 1px solid grey;
31+
border-radius: 5px;
32+
outline: none;
33+
color: whitesmoke;
34+
transition: all 0.5s ease;
35+
}
36+
37+
input:focus {
38+
box-shadow: -1px -1px 10px 1px rgba(255, 255, 255, 0.2);
39+
}
40+
41+
.transaction-details {
42+
max-height: 50vh;
43+
overflow-y: auto;
44+
padding-right: 10px;
45+
}
46+
47+
.transaction-details::-webkit-scrollbar {
48+
width: 10px;
49+
}
50+
51+
.transaction-details::-webkit-scrollbar-track {
52+
background-color: #999;
53+
border-radius: 10px;
54+
}
55+
56+
.transaction-details::-webkit-scrollbar-thumb {
57+
background: #2dcca6;
58+
border-radius: 10px;
59+
}
60+
61+
.income {
62+
border: 1px solid #2dcca6;
63+
color: #2dcca6;
64+
}
65+
66+
.expense {
67+
border: 1px solid #c54949;
68+
color: #c54949;
69+
}
70+
71+
.ri-close-line {
72+
cursor: pointer;
73+
}
74+
75+
@media (max-width: 576px) {
76+
/* Styles for screens below 576px */
77+
.transaction-details::-webkit-scrollbar {
78+
width: 5px;
79+
}
80+
}
81+
82+
@media (min-width: 992px) {
83+
/* Styles for screens above 992px */
84+
.col > div {
85+
width: 50%;
86+
}
87+
}

0 commit comments

Comments
 (0)