Skip to main content

Frontend Overview

The frontend is a React single-page application built with TypeScript, Tailwind CSS, and shadcn/ui components.

Stack

TechnologyVersionPurpose
React18UI framework
TypeScript5Type safety
Tailwind CSS3Utility-first styling
shadcn/uilatestComponent primitives
TanStack React Query5Server state management
React Router6Client-side routing
Vite5Build tool and dev server
sonnerlatestToast notifications

Architecture

State Management

  • Server state: Managed by TanStack React Query (caching, refetching, mutations)
  • URL state: Filter parameters persisted in URL search params
  • Local state: React useState for form inputs and UI state
  • No global state management library (Redux, Zustand) — not needed

Query Keys

All React Query keys are centralized in lib/query-keys.ts for consistency:

export const queryKeys = {
clients: {
all: ['clients'] as const,
detail: (key: string) => ['clients', key] as const,
worklogs: (key: string, from: string, to: string) =>
['clients', key, 'worklogs', from, to] as const,
},
invoices: {
all: ['invoices'] as const,
list: (filters: InvoiceFilters) => ['invoices', filters] as const,
detail: (id: string) => ['invoices', id] as const,
editHistory: (id: string) => ['invoices', id, 'edit-history'] as const,
},
};

Development

# Start dev server (port 5173)
make run-frontend

# Or directly
cd frontend && npm run dev

# Lint
cd frontend && npx eslint .

# Format
cd frontend && npx prettier --write "src/**/*.{ts,tsx,css}"

Configuration

The frontend proxies API requests to the backend via Vite's dev server proxy:

// vite.config.ts
server: {
port: 5173,
proxy: {
'/api': {
target: 'http://localhost:8081',
changeOrigin: true,
},
},
}

Conventions

  • Components: PascalCase (InvoiceRegistry.tsx)
  • Hooks: use{Name} (useInvoices.ts)
  • API functions: verb + noun (fetchInvoices, generateInvoice)
  • Event handlers: handle{Event} (handleSubmit, handleDelete)
  • Search inputs: Debounced at 300ms
  • Toasts: sonner with contextual messages
  • Accessibility: aria-label on icon buttons, aria-invalid on form errors, keyboard navigation