Description:
I’m encountering an issue with the spent amount calculation in my budget tracker application. I’m using React on the frontend and Express.js with SQLite3 on the backend.
In my application, I fetch budget data from the backend, along with associated expenses. Each budget has an associated array of expenses. However, when I calculate the spent amount for each budget based on its associated expenses, I’m encountering unexpected behavior.
Specifically, the spent amount is consistently showing up as 0, and the remaining amount as the initial budget amount, even though expenses exist for some budgets.
Here’s what I’ve already verified and tried:
-
Expense Data: I’ve confirmed that the expenses fetched from the
backend include the budgetId property and that it corresponds to the
correct budget. -
Budget IDs: I’ve ensured that the id passed to the
calculateSpentByBudget function matches the budgetId of the budget
I’m calculating the spent amount for. -
Parsing of Amounts: I’ve verified that the amount property of each
expense is parsed correctly as a number.
Debugging Attempts: I’ve added console.log statements within the reduce function in calculateSpentByBudget to inspect the data during the calculation process. However, I haven’t been able to identify the source of the issue.
I suspect there might be an issue with how I’m handling the expense data or the calculation logic, but I’m having trouble pinpointing the exact cause.
The calculation code:
const calculateSpentByBudget = (budgetId) => {
const budgetSpent = expenses.reduce((acc, expense) => {
if (expense.budgetId !== budgetId) return acc;
// Check if expense.amount is a valid number
const amount = parseFloat(expense.amount);
if (!isNaN(amount)) {
acc += amount;
}
return acc;
}, 0);
return budgetSpent;
};
it was previously this code but it kept showing up as “Nan” for both spent and remaining
const calculateSpentByBudget = (budgetId) => {
const budgetSpent = expenses.reduce((acc, expense) =>{
if(expense.budgetId !== budgetId) return acc
return acc += expense.amount
}, 0)
return budgetSpent;
}
helpers.js
//formating percentages
export const formatPercentage = (amt) => {
return amt.toLocaleString(undefined,{
style: 'percent',
minimumFractionDigits: 0,
})
}
//format currency
export const formatCurrency = (amt) => {
return amt.toLocaleString(undefined,{
style: 'currency',
currency: 'USD'
})
}
BudgetItem Page where it is being used
const BudgetItem = ({ budget, showDelete = false }) => {
const { id, name, amount, color } = budget;
const [expenses, setExpenses] = useState([]);
const [expensesExist, setExpensesExist] = useState(false);
useEffect(() => {
// Fetch expenses from your backend when the component mounts
fetchExpense();
}, []);
const fetchExpense = async () => {
try {
const response = await fetch('http://localhost:3000/expenses');
if (!response.ok) {
throw new Error('Failed to fetch expenses');
}
const data = await response.json();
setExpenses(data);
setExpensesExist(data.Length > 0);
} catch (error) {
console.error('Error fetching expenses:', error);
toast.error('Failed to fetch expenses');
}
};
const calculateSpentByBudget = (budgetId) => {
const budgetSpent = expenses.reduce((acc, expense) => {
if (expense.budgetId !== budgetId) return acc;
// Check if expense.amount is a valid number
const amount = parseFloat(expense.amount);
if (!isNaN(amount)) {
acc += amount;
}
return acc;
}, 0);
return budgetSpent;
};
const spent = calculateSpentByBudget(id);
return (
<div
className="budget"
style={{
"--accent": color,
}}
>
<div className="progress-text">
<h3>{name}</h3>
<p>{formatCurrency(amount)} Budgeted</p>
</div>
<progress max={amount} value={spent}>
{formatPercentage(spent / amount)}
</progress>
<div className="progress-text">
<small>{formatCurrency(spent)} spent</small>
<small>{formatCurrency(amount - spent)} remaining</small>
</div>
{showDelete ? (
<div className="flex-sm">
<Form
method="post"
action="delete"
onSubmit={(event) => {
if (
!confirm(
"Are you sure you want to permanently delete this budget?"
)
) {
event.preventDefault();
}
}}
>
<button type="submit" className="btn">
<span>Delete Budget</span>
<TrashIcon width={20} />
</button>
</Form>
</div>
) : (
<div className="flex-sm">
<Link to={`/budget/${id}`} className="btn">
<span>View Details</span>
<BanknotesIcon width={20} />
</Link>
</div>
)}
</div>
);
};
export default BudgetItem;
I am fetching the budgets from the dashboard page
function Dashboard() {
const location = useLocation();
const [budgetsExist, setBudgetsExist] = useState(false);
const [budgets, setBudgets] = useState([]);
useEffect(() => {
// Fetch budgets from your backend when the component mounts
fetchBudgets();
}, []);
const fetchBudgets = async () => {
try {
const response = await fetch('http://localhost:3000/budgets');
if (!response.ok) {
throw new Error('Failed to fetch budgets');
}
const data = await response.json();
setBudgets(data); // Set the fetched budgets
setBudgetsExist(data.length > 0); // Set budgetsExist based on whether budgets array is empty or not
} catch (error) {
console.error('Error fetching budgets:', error);
toast.error('Failed to fetch budgets');
}
};
return (
<>
<div className="dashboard">
{budgetsExist ? ( // Render appropriate content based on budgetsExist
<div className="grid-lg">
<div className="flex-lg">
<AddBudgetForm />
<AddExpenseForm budgets={budgets} />
</div>
<h2>Existing Budgets</h2>
<div className="budgets">
{
budgets.map((budget) => (
<BudgetItem key={budget.id} budget={budget} />
))
}
</div>
</div>
) : (
<div className="grid-sm">
<p>Personal budgeting is the secret to financial freedom.</p>
<p>Create a budget to get started!</p>
<AddBudgetForm />
</div>
)}
</div>
</>
);
}
export default Dashboard
Backend code for fetching the budget and expenses also the table used to create expense and budget
// Endpoint to fetch budgets
app.get('/budgets', (req, res) => {
const sql = `SELECT * FROM budgets`;
db.all(sql, [], (err, rows) => {
if (err) {
console.error('Error fetching budgets:', err);
return res.status(500).json({ error: 'Failed to fetch budgets' });
}
res.status(200).json(rows); // Send the fetched budgets as JSON response
});
});
// Endpoint to fetch expenses
app.get('/expenses', (req, res) => {
const sql = `SELECT * FROM expenses`;
db.all(sql, [], (err, rows) => {
if (err) {
console.error('Error fetching expenses:', err);
return res.status(500).json({ error: 'Failed to fetch expenses' });
}
res.status(200).json(rows); // Send the fetched expenses as JSON response
});
});
// Create expenses table if it doesn't exist
db.run(`CREATE TABLE IF NOT EXISTS expenses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
newExpense TEXT NOT NULL,
createdAt INTEGER NOT NULL,
newExpenseAmount REAL NOT NULL,
budgetId INTEGER NOT NULL,
FOREIGN KEY (budgetId) REFERENCES budgets(id)
)`, (err) => {
if (err) {
console.error('Error creating expenses table:', err);
} else {
console.log('Expenses table created successfully');
}
});
// Create budgets table
db.run(`CREATE TABLE IF NOT EXISTS budgets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
createdAt INTEGER NOT NULL,
amount REAL NOT NULL,
color TEXT NOT NULL
)`, (err) => {
if (err) {
console.error('Error creating budgets table:', err);
} else {
console.log('Budgets table created successfully');
}
});
Could someone please review my code snippets and provide guidance on how to troubleshoot and resolve this issue?
I Apologize if the snippets are too much I just thought it would be better to provide as much as possible just not to leave anything out.
Thank you in advance for your assistance!