frontend Tutorial
Building an Expense Tracker Frontend - Part 3: Dashboard & Expenses List
In this series
- •Building an Expense Tracker Frontend - Part 1: Setup & UI Framework
- •Building an Expense Tracker Frontend - Part 2: Auth Integration
- •Building an Expense Tracker Frontend - Part 3: Dashboard & Expenses List
- •Building an Expense Tracker Frontend - Part 4: Add/Edit Expense Forms
In this part, we will build the main Dashboard of our application, where users can see a list of their recent expenses.
Expenses API
First, let's define the API call to fetch expenses.
// src/api/expenses.ts
import axios from 'axios';
const API_URL = 'http://localhost:9000/api';
export interface Expense {
id: number;
description: string;
amount: number;
currency: string;
date: string;
category: string;
}
export const getExpenses = async (userId: number) => {
const response = await axios.get(`${API_URL}/users/${userId}/expenses`);
return response.data;
};
Expense List Component
We'll use useQuery from TanStack Query to fetch the data. This handles loading and error states for us automatically.
// src/components/ExpenseList.tsx
import React from 'react';
import { useQuery } from '@tanstack/react-query';
import { getExpenses, Expense } from '../api/expenses';
interface ExpenseListProps {
userId: number;
}
const ExpenseList: React.FC<ExpenseListProps> = ({ userId }) => {
const { isPending, error, data } = useQuery({
queryKey: ['expenses', userId],
queryFn: () => getExpenses(userId),
});
if (isPending) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Date</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Description</th>
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase">Amount</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{data.map((expense: Expense) => (
<tr key={expense.id}>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{new Date(expense.date).toLocaleDateString()}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{expense.description}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 text-right">
{expense.amount.toFixed(2)} {expense.currency}
</td>
</tr>
))}
</tbody>
</table>
);
};
export default ExpenseList;
Dashboard Page
Finally, we create the Dashboard page to host our list.
// src/pages/DashboardPage.tsx
import React from 'react';
import ExpenseList from '../components/ExpenseList';
const DashboardPage: React.FC = () => {
const userId = 1; // Replace with real user ID from auth context
return (
<div className="min-h-screen bg-gray-100">
<nav className="bg-white shadow-sm">
{/* Navigation Bar */}
</nav>
<main className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
<div className="bg-white shadow overflow-hidden sm:rounded-lg">
<ExpenseList userId={userId} />
</div>
</main>
</div>
);
};
export default DashboardPage;
Next Steps
In the next part, we will create the forms to Add and Edit expenses.
Continue to Part 4: Add/Edit Expense Forms
