frontend Tutorial

Building an Expense Tracker Frontend - Part 4: Add/Edit Expense Forms

In this final part of the frontend series, we will implement the ability to Add new expenses. We'll create a form component and use TanStack Query to handle the data submission and cache invalidation.

Updating the API

We need a function to send the new expense data to the backend.

// src/api/expenses.ts
export const createExpense = async (userId: number, expense: Omit<Expense, 'id'>) => {
  const response = await axios.post(`${API_URL}/users/${userId}/expenses`, expense);
  return response.data;
};

Expense Form Component

We'll create a form that captures the expense details. We use useMutation to send the data and useQueryClient to refresh the expense list automatically upon success.

// src/components/ExpenseForm.tsx
import React, { useState } from 'react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { createExpense } from '../api/expenses';

interface ExpenseFormProps {
  userId: number;
  onSuccess?: () => void;
}

const ExpenseForm: React.FC<ExpenseFormProps> = ({ userId, onSuccess }) => {
  // State for form fields...
  const queryClient = useQueryClient();

  const mutation = useMutation({
    mutationFn: () => createExpense(userId, { /* form data */ }),
    onSuccess: () => {
      // Invalidate the 'expenses' query to refetch the list
      queryClient.invalidateQueries({ queryKey: ['expenses', userId] });
      if (onSuccess) onSuccess();
    },
  });

  // ... render form
};

Integrating into Dashboard

Now you can add this form to your Dashboard, perhaps in a modal or a side panel.

Conclusion

You have successfully built a full-stack Expense Tracker!

  • Backend: Scala 3, Play Framework, Macwire, Pekko, MySQL.
  • Frontend: React, TypeScript, TailwindCSS, TanStack Query.

In the next series, we will look at deploying this application to the cloud.