Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions Domains/Frontend/MiniProjects/expense_tracker/README.md
Original file line number Diff line number Diff line change
@@ -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
100 changes: 100 additions & 0 deletions Domains/Frontend/MiniProjects/expense_tracker/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Expense Tracker</title>
<!-- Load Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Link to external CSS file (must be in the same directory) -->
<link rel="stylesheet" href="style.css">
</head>
<body>

<div id="app" class="p-4 md:p-8 lg:p-12 max-w-4xl mx-auto">
<header class="text-center mb-8">
<!-- Dark mode text color -->
<h1 class="text-4xl md:text-5xl font-extrabold text-blue-300 tracking-tight">
BudgetFlow Tracker
</h1>
<!-- Dark mode text color -->
<p class="text-gray-400 mt-2">Manage your money in real-time.</p>
<p class="text-xs mt-1 text-gray-500" id="user-info">Authenticating...</p>
</header>

<!-- Balance Summary Section -->
<section class="grid grid-cols-3 gap-4 mb-8">
<div class="p-4 rounded-xl main-card text-center transition-transform hover:scale-[1.01] duration-300">
<!-- Dark mode text color -->
<h2 class="text-lg font-semibold text-gray-400">Balance</h2>
<p id="balance" class="text-3xl font-bold text-blue-400 mt-1">--</p>
</div>
<div class="p-4 rounded-xl main-card text-center transition-transform hover:scale-[1.01] duration-300">
<!-- Dark mode text color -->
<h2 class="text-lg font-semibold text-gray-400">Income</h2>
<p id="income" class="text-3xl font-bold text-emerald-400 mt-1">--</p>
</div>
<div class="p-4 rounded-xl main-card text-center transition-transform hover:scale-[1.01] duration-300">
<!-- Dark mode text color -->
<h2 class="text-lg font-semibold text-gray-400">Expenses</h2>
<p id="expense" class="text-3xl font-bold text-rose-400 mt-1">--</p>
</div>
</section>

<!-- Add Transaction Form -->
<section class="main-card p-6 rounded-xl mb-8">
<!-- Dark mode text color -->
<h2 class="text-2xl font-bold mb-4 text-blue-300">Add New Transaction</h2>
<form id="transaction-form" class="space-y-4">
<div>
<!-- Dark mode label text color -->
<label for="description" class="block text-sm font-medium text-gray-400 mb-1">Description</label>
<!-- Dark theme input styling -->
<input type="text" id="description" placeholder="E.g., Salary, Coffee, Rent" required
class="w-full p-3 rounded-lg bg-gray-700 border border-gray-600 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-white transition duration-200">
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<!-- Dark mode label text color -->
<label for="amount" class="block text-sm font-medium text-gray-400 mb-1">Amount ($)</label>
<!-- Dark theme input styling -->
<input type="number" id="amount" placeholder="50.00" step="0.01" required
class="w-full p-3 rounded-lg bg-gray-700 border border-gray-600 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-white transition duration-200">
</div>
<div>
<!-- Dark mode label text color -->
<label for="type" class="block text-sm font-medium text-gray-400 mb-1">Type</label>
<!-- Dark theme select styling -->
<select id="type" required
class="w-full p-3 rounded-lg bg-gray-700 border border-gray-600 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-white transition duration-200 appearance-none cursor-pointer">
<option value="income" class="bg-gray-800">Income</option>
<option value="expense" class="bg-gray-800">Expense</option>
</select>
</div>
</div>
<!-- Button colors remain the same for accent -->
<button type="submit" id="submit-btn"
class="animated-btn w-full py-3 mt-4 rounded-lg font-bold text-lg text-white bg-emerald-600 hover:bg-emerald-500 focus:outline-none focus:ring-4 focus:ring-emerald-300/50 transition duration-200 shadow-lg shadow-emerald-600/30">
Add Transaction
</button>
</form>
<!-- Dark mode error text color -->
<p id="error-message" class="text-rose-400 mt-2 text-center hidden"></p>
</section>

<!-- Transaction History Section -->
<section class="main-card p-6 rounded-xl">
<!-- Dark mode text color -->
<h2 class="text-2xl font-bold mb-4 text-blue-300">Transaction History</h2>
<div id="transactions-list" class="space-y-3">
<!-- Transactions will be inserted here by JavaScript -->
<!-- Dark mode loading text color -->
<p id="loading-message" class="text-gray-400 text-center py-4">Loading transactions...</p>
</div>
</section>
</div>

<!-- Link to external JavaScript file (must be in the same directory) -->
<script src="script.js"></script>
</body>
</html>
122 changes: 122 additions & 0 deletions Domains/Frontend/MiniProjects/expense_tracker/script.js
Original file line number Diff line number Diff line change
@@ -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 = `<p id="loading-message" class="text-gray-400 text-center py-4">No transactions yet. Data is temporary.</p>`;
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 = `
<div class="flex-1 min-w-0 mr-4">
<p class="font-semibold text-gray-200 truncate">${t.description}</p>
<p class="text-xs text-gray-500 mt-0.5">${new Date(t.timestamp).toLocaleDateString()}</p>
</div>
<div class="flex items-center space-x-4">
<span class="font-bold text-lg ${colorClass}">
${sign}${formattedAmount}
</span>
<button onclick="deleteTransaction('${t.id}')"
class="animated-btn p-2 rounded-full bg-red-600 hover:bg-red-500 text-white opacity-80 group-hover:opacity-100 transition duration-150">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm4 0a1 1 0 10-2 0v6a1 1 0 102 0V8z" clip-rule="evenodd" />
</svg>
</button>
</div>
`;
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();
});
45 changes: 45 additions & 0 deletions Domains/Frontend/MiniProjects/expense_tracker/style.css
Original file line number Diff line number Diff line change
@@ -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;
}