Building the ExpenseTracker Component
Building the ExpenseTracker Component
The ExpenseTracker component contains the application's complete expense-tracking functionality. It allows users to enter their monthly income, add expenses by selecting or creating a category, view all added expenses, remove expenses when needed, and automatically calculate the Total Expense and Remaining Balance.
Whenever a user adds or deletes an expense, the component's state is updated, causing the UI to re-render and instantly display the latest values.
To keep the overall project organized, this functionality was developed inside a separate components folder as a child component, while the App component acts as the parent component that imports and renders it.
Additionally, toLocaleString("en-IN") is used to display income, expenses, and balance values in the standard Indian number format, making large amounts easier to read and understand.
File Path: ExpenseTracker\src\components\expenseTracker.jsx
import React, { useState } from "react";
function ExpenseTracker() {
const [income, setIncome] = useState("");
const [category, setCategory] = useState("Apparel");
const [amount, setAmount] = useState("");
const [expenses, setExpenses] = useState([]);
const [customCategory, setCustomCategory] = useState("");
const addExpense = () => {
if (!income || Number(income) <= 0) {
alert("Please enter your monthly income first!");
return;
}
if (!amount || Number(amount) <= 0) return;
const expenseName =
category === "Other Expense"
? customCategory.trim()
: category;
if (!expenseName) {
alert("Please name the expense");
return;
}
const categoryExists = expenses.some(
(expense) =>
expense.category.toLowerCase() ===
expenseName.toLowerCase()
);
if (categoryExists) {
alert("This category already exists!");
return;
}
const newExpense = {
id: Date.now(),
category: expenseName,
amount: Number(amount),
};
setExpenses([...expenses, newExpense]);
setAmount("");
setCustomCategory("");
};
const deleteExpense = (id) => {
setExpenses(expenses.filter((expense) => expense.id !== id));
};
const totalExpense = expenses.reduce(
(total, expense) => total + expense.amount,
0
);
const balance = Number(income || 0) - totalExpense;
return (
<>
<div className="head-text flex flex-col items-center w-full max-w-6xl rounded-2xl py-6 px-4">
<h1 className="mb-2 text-3xl md:text-4xl text-center">
Expense Tracker
</h1>
<h2 className="text-base md:text-lg text-center font-semibold">
<i>Manage your daily expenses</i>
</h2>
</div>
<div className="data-display-section flex flex-col lg:flex-row w-full max-w-6xl gap-6 rounded-2xl p-4 justify-between items-center mt-6">
<div className="total-income p-6 rounded-2xl w-full lg:w-[35%]">
<h2 className="mb-4 text-xl md:text-2xl text-center font-semibold">
Monthly Income
</h2>
<input
type="text"
value={income}
onChange={(e) => setIncome(e.target.value)}
placeholder="₹ Enter monthly income"
className="w-full border border-slate-600 rounded-xl px-4 py-3 outline-none bg-white text-black"
/>
</div>
<div className="summary-section rounded-2xl p-6 w-full lg:w-[60%]">
<h2 className="mb-4 text-xl md:text-2xl text-center font-semibold">
Summary
</h2>
{/* <div className="boxes flex flex-col md:flex-row gap-4"> */}
<div className="boxes grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div className="income-box flex-1 bg-white p-5 rounded-2xl shadow-sm border border-slate-200">
<h3 className="text-base md:text-lg text-slate-700">Income</h3>
<p className="text-xl md:text-2xl font-bold">
₹{Number(income).toLocaleString("en-IN")}
</p>
</div>
<div className="expense-box flex-1 bg-white p-5 rounded-2xl shadow-sm border border-slate-200">
<h3 className="text-base md:text-lg text-slate-700">Expense</h3>
<p className="text-xl md:text-2xl font-bold">
₹{totalExpense.toLocaleString("en-IN")}
</p>
</div>
<div className="total-balance-box flex-1 bg-white p-5 rounded-2xl shadow-sm border border-slate-200">
<h3 className="text-base md:text-lg text-slate-700">Balance</h3>
<p className="text-xl md:text-2xl font-bold">
₹{balance.toLocaleString("en-IN")}
</p>
</div>
</div>
</div>
</div>
<div className="expense-section flex flex-col lg:flex-row mt-6 mb-6 gap-6 w-full max-w-6xl rounded-2xl p-4">
<div className="add-expense flex flex-col p-6 rounded-2xl w-full lg:w-1/2">
<h2 className="text-xl md:text-2xl text-center font-semibold">
Expenses
</h2>
<label htmlFor="expenses" className="text-lg mt-4">
Category
</label>
<select
name="expenses"
id="expenses"
value={category}
onChange={(e) => setCategory(e.target.value)}
className="border border-slate-600 rounded-xl px-4 py-3 mt-2 outline-none"
>
<option>Other Expense</option>
<option>Apparel</option>
<option>Food</option>
<option>Travel</option>
<option>Mobile Recharge</option>
</select>
{category === "Other Expense" && (
<input
type="text"
value={customCategory}
onChange={(e) => setCustomCategory(e.target.value)}
placeholder="Name the expense"
className="border border-slate-600 rounded-xl px-4 py-3 mt-4 outline-none"
/>
)}
<label htmlFor="expense-amount" className="text-lg mt-4">
Amount (in ₹):
</label>
<input
type="number"
id="expense-amount"
name="expense-amount"
min="1"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Enter amount"
className="border border-slate-600 rounded-xl px-4 py-3 mt-2 outline-none"
/>
<button
onClick={addExpense}
className="w-full p-3 rounded-lg text-white bg-black mt-4 hover:opacity-90"
>
Add Expense
</button>
</div>
<div className="expense-list bg-white p-6 rounded-2xl shadow-sm border border-gray-400 w-full lg:w-1/2">
<h2 className="mb-4 text-xl md:text-2xl text-center font-semibold">
Expense List
</h2>
{expenses.length === 0 ? (
<p className="text-lg text-slate-900 my-6">
No expenses added yet.
</p>
) : (
expenses.map((expense) => (
<div
key={expense.id}
className="text-lg flex justify-between py-3 border-b border-slate-200"
>
<span>{expense.category}</span>
<div className="flex items-center gap-4">
<span>
₹{expense.amount.toLocaleString("en-IN")}
</span>
<button
onClick={() => deleteExpense(expense.id)}
className="text-red-500 hover:text-red-400 font-extrabold"
title="Clear Expense"
>
✕
</button>
</div>
</div>
))
)}
<div className="text-lg flex justify-between py-3 font-bold">
<span>Total Expense:</span>
<span>₹{totalExpense.toLocaleString("en-IN")}</span>
</div>
</div>
</div>
</>
);
}
export default ExpenseTracker;









