diff --git a/Domains/Frontend/MiniProjects/expense_tracker/README.md b/Domains/Frontend/MiniProjects/expense_tracker/README.md new file mode 100644 index 00000000..09d51f63 --- /dev/null +++ b/Domains/Frontend/MiniProjects/expense_tracker/README.md @@ -0,0 +1,42 @@ +**Contributor:** alisha1510 + +# Expense Tracker + +A dynamic web application to help users track their income, expenses, and balance in real-time. Features interactive charts, a clean interface, and a user-friendly way to manage personal finances. + +## 🌟 Features + +* **Real-Time Tracking** – Add income and expenses instantly, see updates in your balance. +* **Transaction History** – View, sort, and delete past transactions easily. + + +## 🎯 How to Use + +1.Open the web application in a browser. +2.Add a transaction using the Add Transaction form (income or expense). +3.Enter description, amount, and type. +4.Submit to update your balance and charts instantly. +5.View your transaction history below and delete items if needed. + + +## ⚠️ Important Disclaimer + +**For personal finance tracking only!** + +This project is intended to help manage budgets and track expenses. Please do not use this app for financial advice or professional accounting purposes. + + +## 🤝 Contributing + +Contributions, issues, and feature requests are welcome! Feel free to check the issues page. + +## 👤 Author + +**Alisha Sheikh** +- GitHub: [@alisha1510](https://github.com/alisha1510) + + +--- + + +Made with 💜 for Hacktoberfest and the Open Source Community \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/expense_tracker/index.html b/Domains/Frontend/MiniProjects/expense_tracker/index.html new file mode 100644 index 00000000..9eeca12e --- /dev/null +++ b/Domains/Frontend/MiniProjects/expense_tracker/index.html @@ -0,0 +1,100 @@ + + + + + + Dynamic Expense Tracker + + + + + + + +
+
+ +

+ BudgetFlow Tracker +

+ +

Manage your money in real-time.

+

Authenticating...

+
+ + +
+
+ +

Balance

+

--

+
+
+ +

Income

+

--

+
+
+ +

Expenses

+

--

+
+
+ + +
+ +

Add New Transaction

+
+
+ + + + +
+
+
+ + + + +
+
+ + + + +
+
+ + +
+ + +
+ + +
+ +

Transaction History

+
+ + +

Loading transactions...

+
+
+
+ + + + + diff --git a/Domains/Frontend/MiniProjects/expense_tracker/script.js b/Domains/Frontend/MiniProjects/expense_tracker/script.js new file mode 100644 index 00000000..778820e1 --- /dev/null +++ b/Domains/Frontend/MiniProjects/expense_tracker/script.js @@ -0,0 +1,122 @@ +document.addEventListener("DOMContentLoaded", () => { + let localTransactions = []; + + const userInfo = document.getElementById("user-info"); + const form = document.getElementById("transaction-form"); + const list = document.getElementById("transactions-list"); + const errorMessage = document.getElementById("error-message"); + + const balanceEl = document.getElementById("balance"); + const incomeEl = document.getElementById("income"); + const expenseEl = document.getElementById("expense"); + + userInfo.textContent = "Local Mode (Data will not save)"; + console.log("Running in Local Mode. Data is temporary."); + + const renderTransactions = () => { + list.innerHTML = ""; + + if (localTransactions.length === 0) { + list.innerHTML = `

No transactions yet. Data is temporary.

`; + return; + } + + localTransactions.forEach((t) => { + const isExpense = t.amount < 0; + const sign = isExpense ? "-" : "+"; + const colorClass = isExpense ? "text-rose-400" : "text-emerald-400"; + const formattedAmount = `$${Math.abs(t.amount).toFixed(2)}`; + + const item = document.createElement("div"); + item.id = `transaction-${t.id}`; + item.className = + "flex justify-between items-center p-4 rounded-xl main-card transition-all duration-300 hover:bg-gray-700/50 group"; + item.innerHTML = ` +
+

${t.description}

+

${new Date(t.timestamp).toLocaleDateString()}

+
+
+ + ${sign}${formattedAmount} + + +
+ `; + list.appendChild(item); + }); + }; + + const updateSummary = () => { + const income = localTransactions + .filter((t) => t.amount > 0) + .reduce((acc, t) => acc + t.amount, 0); + const expense = localTransactions + .filter((t) => t.amount < 0) + .reduce((acc, t) => acc + t.amount, 0); + + const totalExpense = Math.abs(expense); + const balance = income + expense; + + incomeEl.textContent = `$${income.toFixed(2)}`; + expenseEl.textContent = `$${totalExpense.toFixed(2)}`; + balanceEl.textContent = `$${balance.toFixed(2)}`; + balanceEl.className = `text-3xl font-bold mt-1 ${ + balance >= 0 ? "text-blue-400" : "text-rose-500" + }`; + }; + + const addTransaction = (e) => { + e.preventDefault(); + const description = document.getElementById("description").value.trim(); + const amountInput = document.getElementById("amount"); + const type = document.getElementById("type").value; + + let amount = parseFloat(amountInput.value); + if (!description || isNaN(amount) || amount <= 0) { + errorMessage.textContent = + "Please enter a valid description and amount."; + errorMessage.classList.remove("hidden"); + return; + } + + errorMessage.classList.add("hidden"); + const sign = type === "expense" ? -1 : 1; + amount = amount * sign; + + const transaction = { + id: crypto.randomUUID(), + description, + amount, + type, + timestamp: new Date().toISOString(), + }; + + localTransactions.unshift(transaction); + renderTransactions(); + updateSummary(); + + form.reset(); + errorMessage.textContent = + "Added successfully! (Temporary data - local mode)"; + errorMessage.classList.remove("hidden"); + setTimeout(() => errorMessage.classList.add("hidden"), 3000); + }; + + window.deleteTransaction = (id) => { + localTransactions = localTransactions.filter((t) => t.id !== id); + renderTransactions(); + updateSummary(); + }; + + form.addEventListener("submit", addTransaction); + + // Initial render + renderTransactions(); + updateSummary(); +}); diff --git a/Domains/Frontend/MiniProjects/expense_tracker/style.css b/Domains/Frontend/MiniProjects/expense_tracker/style.css new file mode 100644 index 00000000..1fda8d6d --- /dev/null +++ b/Domains/Frontend/MiniProjects/expense_tracker/style.css @@ -0,0 +1,45 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap'); +body { + font-family: 'Inter', sans-serif; + /* Blue gradient background */ + background: linear-gradient(135deg, #1f2937 0%, #0f172a 100%); + min-height: 100vh; + /* Light text color */ + color: #e5e7eb; + overflow-x: hidden; /* Prevent horizontal scroll */ + /* Padding to allow scrolling space at the bottom */ + padding-bottom: 2rem; +} +/* Custom Scrollbar for dark aesthetics */ +::-webkit-scrollbar { + width: 8px; +} +::-webkit-scrollbar-track { + background: #111827; +} +::-webkit-scrollbar-thumb { + background: #4b5563; + border-radius: 10px; +} +::-webkit-scrollbar-thumb:hover { + background: #6b7280; +} + +/* Custom Button Animation */ +.animated-btn { + transition: all 0.2s ease-in-out; +} +.animated-btn:hover { + transform: translateY(-2px) scale(1.02); + box-shadow: 0 10px 15px -3px rgba(16, 185, 129, 0.2), 0 4px 6px -2px rgba(16, 185, 129, 0.1); +} +.animated-btn:active { + transform: translateY(0) scale(0.98); + box-shadow: none; +} +/* Custom styling for the main card - dark background */ +.main-card { + background-color: #1f2937; + box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.3), 0 10px 10px -5px rgba(0, 0, 0, 0.1); + border: 1px solid #374151; +}