diff --git a/assets/expense-tracker-preview.png b/assets/expense-tracker-preview.png new file mode 100644 index 00000000..b158d912 Binary files /dev/null and b/assets/expense-tracker-preview.png differ diff --git a/en/beginner-projects/expense-tracker.md b/en/beginner-projects/expense-tracker.md new file mode 100644 index 00000000..4a7027e6 --- /dev/null +++ b/en/beginner-projects/expense-tracker.md @@ -0,0 +1,43 @@ +# 💰 Expense Tracker + +![Expense Tracker Preview](../../assets/expense-tracker-preview.png) + +## Description + +A simple **Expense Tracker** built using **HTML, CSS, and JavaScript (ES Modules)** that allows users to manage their daily income and expenses. Users can **add, edit, and delete** transactions, view their **balance summary**, and store data locally using **localStorage** — all without a backend. + +## Features + +- Add new transactions (income or expense) +- Edit existing transactions +- Delete unwanted transactions +- View total balance, income, and expense summaries +- Persistent data storage using `localStorage` +- Clean and responsive UI design + +## Concepts Practiced + +- DOM manipulation +- Working with arrays and objects +- Event handling and form submission +- Data persistence using `localStorage` +- Conditional rendering and dynamic UI updates +- Modular JavaScript (`index.mjs`) + +## Bonus Challenge + +- Add a **dark mode toggle** in the navbar 🌙 +- Show a **monthly expense chart** using a JS chart library +- Add a **filter/search** option for transactions +- Allow users to **export data** as CSV + +## Live Demo + +
+ +
diff --git a/examples/Expense-Tracker/README.md b/examples/Expense-Tracker/README.md new file mode 100644 index 00000000..0117b920 --- /dev/null +++ b/examples/Expense-Tracker/README.md @@ -0,0 +1,40 @@ +# 💰 Expense Tracker + +A simple and interactive **Expense Tracker** built using **HTML, CSS, and modern JavaScript (ES Modules)**. +It helps users manage their daily income and expenses, view summaries, and store data locally — all without a backend. + +## Features + +- ➕ **Add new transactions** — income or expense. +- ✏️ **Edit transactions** — update existing entries easily. +- ❌ **Delete transactions** you no longer need. +- 💵 **Live balance summary** showing total, income, and expenses. +- 💾 **Data persistence** using `localStorage` (no backend required). +- 📱 **Clean and responsive UI** — works on both desktop and mobile. + +## Files + +- `index.html` — main structure and layout of the app. +- `styles.css` — styling, layout, and responsive design. +- `index.mjs` — handles core functionality like adding, editing, deleting, and storing transactions. + +## How to Use + +1. Open `index.html` in your browser (Chrome, Edge, or Firefox recommended). +2. Enter a **description** and **amount**. + - Use positive numbers for income (e.g., `+5000`). + - Use negative numbers for expenses (e.g., `-1200`). +3. Click **Add Transaction** to save it. +4. View your total **balance**, **income**, and **expense** at a glance. +5. Edit or delete transactions anytime — all changes are saved automatically. + +## Notes + +- Data is stored locally in the browser using **localStorage**. +- The app automatically loads your saved data on refresh. +- Built entirely with **vanilla JS, HTML, and CSS** — no external libraries used. +- Great for beginners learning **DOM manipulation, events, and localStorage**. + +--- + +✨ **Easily track where your money goes with the Expense Tracker!** diff --git a/examples/Expense-Tracker/index.html b/examples/Expense-Tracker/index.html new file mode 100644 index 00000000..76dfd866 --- /dev/null +++ b/examples/Expense-Tracker/index.html @@ -0,0 +1,47 @@ + + + + + + Expense Tracker + + + +
+

Expense Tracker

+ +
+

Your Balance

+

₹0

+
+ +
+
+

Income

+

₹0

+
+
+

Expense

+

₹0

+
+
+ +

Add New Transaction

+
+ + + +
+ +

Transaction History

+ +
+ + + + diff --git a/examples/Expense-Tracker/index.mjs b/examples/Expense-Tracker/index.mjs new file mode 100644 index 00000000..4adad0b4 --- /dev/null +++ b/examples/Expense-Tracker/index.mjs @@ -0,0 +1,112 @@ +// Select elements +const balanceEl = document.getElementById("balance"); +const incomeEl = document.getElementById("income"); +const expenseEl = document.getElementById("expense"); +const listEl = document.getElementById("transaction-list"); +const form = document.getElementById("transaction-form"); +const textInput = document.getElementById("text"); +const amountInput = document.getElementById("amount"); + +// Load transactions from localStorage +let transactions = JSON.parse(localStorage.getItem("transactions")) || []; + +// Add transaction +function addTransaction(e) { + e.preventDefault(); + + const text = textInput.value.trim(); + const amount = +amountInput.value; + + if (text === "" || amount === 0 || isNaN(amount)) { + alert("Please enter valid description and amount."); + return; + } + + const transaction = { + id: Date.now(), + text, + amount, + }; + + transactions.push(transaction); + updateLocalStorage(); + renderTransactions(); + + textInput.value = ""; + amountInput.value = ""; +} + +// Delete transaction +function deleteTransaction(id) { + transactions = transactions.filter((t) => t.id !== id); + updateLocalStorage(); + renderTransactions(); +} + +// Edit transaction +function editTransaction(id) { + const t = transactions.find((t) => t.id === id); + if (!t) return; + + const newText = prompt("Edit description:", t.text); + const newAmount = parseFloat(prompt("Edit amount:", t.amount)); + + if (newText && !isNaN(newAmount)) { + t.text = newText; + t.amount = newAmount; + updateLocalStorage(); + renderTransactions(); + } +} + +// Update totals +function updateSummary() { + const amounts = transactions.map((t) => t.amount); + const total = amounts.reduce((a, b) => a + b, 0).toFixed(2); + const income = amounts + .filter((a) => a > 0) + .reduce((a, b) => a + b, 0) + .toFixed(2); + const expense = ( + amounts.filter((a) => a < 0).reduce((a, b) => a + b, 0) * -1 + ).toFixed(2); + + balanceEl.textContent = `₹${total}`; + incomeEl.textContent = `₹${income}`; + expenseEl.textContent = `₹${expense}`; +} + +// Render transactions +function renderTransactions() { + listEl.innerHTML = ""; + + transactions.forEach((t) => { + const li = document.createElement("li"); + li.classList.add(t.amount < 0 ? "expense" : "income"); + + li.innerHTML = ` + ${t.text} ₹${t.amount} +
+ + +
+ `; + + listEl.appendChild(li); + }); + + updateSummary(); +} + +// Save to localStorage +function updateLocalStorage() { + localStorage.setItem("transactions", JSON.stringify(transactions)); +} + +// Initialize +renderTransactions(); +form.addEventListener("submit", addTransaction); + +// Expose functions globally (for inline onclick) +window.editTransaction = editTransaction; +window.deleteTransaction = deleteTransaction; diff --git a/examples/Expense-Tracker/styles.css b/examples/Expense-Tracker/styles.css new file mode 100644 index 00000000..ffc08903 --- /dev/null +++ b/examples/Expense-Tracker/styles.css @@ -0,0 +1,125 @@ +* { + box-sizing: border-box; + margin: 0; + padding: 0; + font-family: "Poppins", sans-serif; +} + +body { + background: #f4f4f9; + color: #333; + display: flex; + justify-content: center; + align-items: flex-start; + min-height: 100vh; + padding: 20px; +} + +.container { + background: #fff; + border-radius: 16px; + padding: 30px; + width: 100%; + max-width: 400px; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); +} + +h1 { + text-align: center; + margin-bottom: 20px; + color: #2d3436; +} + +.balance { + text-align: center; + margin-bottom: 20px; +} + +#balance { + font-size: 2rem; + color: #2d3436; + margin-top: 10px; +} + +.summary { + display: flex; + justify-content: space-between; + background: #fafafa; + border-radius: 8px; + padding: 10px 20px; + margin-bottom: 30px; + border: 1px solid #ddd; +} + +.summary div { + text-align: center; +} + +.income p { + color: #27ae60; + font-weight: bold; +} + +.expense p { + color: #c0392b; + font-weight: bold; +} + +form { + display: flex; + flex-direction: column; + gap: 10px; + margin-bottom: 30px; +} + +form input { + padding: 10px; + border-radius: 8px; + border: 1px solid #ccc; +} + +form button { + padding: 10px; + border: none; + border-radius: 8px; + background-color: #0984e3; + color: #fff; + cursor: pointer; + transition: background 0.3s ease; +} + +form button:hover { + background-color: #74b9ff; +} + +.list { + list-style-type: none; + margin-top: 10px; +} + +.list li { + background: #f9f9f9; + border-left: 5px solid #2ecc71; + margin-bottom: 10px; + padding: 10px; + border-radius: 8px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.list li.expense { + border-left-color: #e74c3c; +} + +.list button { + border: none; + background: transparent; + color: #e74c3c; + font-weight: bold; + cursor: pointer; +} + +.list button:hover { + color: #c0392b; +}