This guide explains how to replace mock data with real backend API calls.
- β Dashboard UI fully created
- β Mock data implemented
- β³ Ready for service integration
- β³ Services created (auth, complaint, etc.)
File: src/pages/ComplaintsListPage.tsx
Replace mock data with service:
// OLD - Using mock data
import { MOCK_COMPLAINTS } from '@/services/mock.data';
// NEW - Using service
import { useComplaintsService } from '@/services/hooks';
import { useEffect, useState } from 'react';
export function ComplaintsListPage() {
const [complaints, setComplaints] = useState([]);
const [loading, setLoading] = useState(true);
const complaintService = useComplaintsService();
useEffect(() => {
async function fetchComplaints() {
try {
const data = await complaintService.getAll();
setComplaints(data);
} catch (error) {
console.error('Error fetching complaints:', error);
} finally {
setLoading(false);
}
}
fetchComplaints();
}, []);
if (loading) return <LoadingSpinner />;
// Use complaints instead of MOCK_COMPLAINTS
}File: src/pages/DashboardPage.tsx
// Import services
import { useComplaintsService } from '@/services/hooks';
import { useNotificationsService } from '@/services/hooks'; // Create if needed
export function DashboardPage() {
const complaintService = useComplaintsService();
const [complaints, setComplaints] = useState([]);
useEffect(() => {
loadComplaints();
}, []);
async function loadComplaints() {
try {
const data = await complaintService.getAll();
setComplaints(data);
} catch (error) {
console.error('Failed to load complaints:', error);
}
}
// Replace MOCK_COMPLAINTS with complaints state
}File: src/pages/NewComplaintPage.tsx
import { useComplaintsService } from '@/services/hooks';
export function NewComplaintPage() {
const complaintService = useComplaintsService();
const [loading, setLoading] = useState(false);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
try {
const response = await complaintService.create(formData);
setSuccess(true);
setTimeout(() => navigate('/dashboard/complaints'), 2000);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}
}
}File: src/pages/ComplaintDetailPage.tsx
import { useComplaintsService } from '@/services/hooks';
export function ComplaintDetailPage() {
const { id } = useParams<{ id: string }>();
const [complaint, setComplaint] = useState(null);
const complaintService = useComplaintsService();
useEffect(() => {
async function fetchComplaint() {
try {
const data = await complaintService.getById(parseInt(id!));
setComplaint(data);
} catch (error) {
console.error('Error fetching complaint:', error);
}
}
fetchComplaint();
}, [id]);
if (!complaint) return <LoadingSpinner />;
return (
// Use complaint data from API instead of mock
);
}interface IComplaintService {
// Get all complaints for current user
getAll(): Promise<Complaint[]>;
// Get single complaint by ID
getById(id: number): Promise<Complaint>;
// Create new complaint
create(data: CreateComplaintRequest): Promise<Complaint>;
// Update complaint
update(id: number, data: UpdateComplaintRequest): Promise<Complaint>;
// Delete complaint
delete(id: number): Promise<void>;
// Get complaints with filters
getFiltered(filters: ComplaintFilters): Promise<Complaint[]>;
}interface IRTIService {
getAll(): Promise<RTIRequest[]>;
getById(id: number): Promise<RTIRequest>;
create(data: CreateRTIRequest): Promise<RTIRequest>;
update(id: number, data: UpdateRTIRequest): Promise<RTIRequest>;
}interface ILandRecordService {
getAll(): Promise<LandRecord[]>;
getById(id: number): Promise<LandRecord>;
verify(id: number): Promise<LandRecord>;
}Component β useState β MOCK_DATA β Render
Component β useService β Axios β Backend API β useState β Render
LoginForm β authService.login() β API β Token stored β Redirect to /dashboard
DashboardPage β useComplaintsService.getAll() β API (with auth header) β MOCK_COMPLAINTS replaced β Render
NewComplaintForm β complaintService.create(data) β API β Complaint created β Redirect to list
ComplaintDetailPage β complaintService.getById(id) β API β Render with real data
Services automatically include auth headers via Axios interceptors:
// axios.service.ts already configured with:
// 1. Authorization header injection
// 2. Token refresh on 401
// 3. Error handling
// All services use this axios instance
const response = await axiosInstance.get('/api/complaints');
// Authorization: Bearer <token> added automaticallyReplace mock paths with your actual backend endpoints:
// src/services/config.ts - Update API endpoints
export const API_ENDPOINTS = {
// Complaints
COMPLAINTS: '/api/complaints',
COMPLAINT_DETAIL: '/api/complaints/:id',
COMPLAINT_CREATE: '/api/complaints',
COMPLAINT_UPDATE: '/api/complaints/:id',
COMPLAINT_DELETE: '/api/complaints/:id',
// RTI
RTI_REQUESTS: '/api/rti',
RTI_REQUEST_DETAIL: '/api/rti/:id',
// Land Records
LAND_RECORDS: '/api/land-records',
LAND_RECORD_DETAIL: '/api/land-records/:id',
// Contracts
CONTRACTS: '/api/contracts',
// Budget
BUDGET: '/api/budget',
};// Current: Done in-component
const filtered = complaints.filter(c => c.status === filterStatus);// Better: Let backend filter
async function getFiltered(filters: ComplaintFilters) {
const response = await axiosInstance.get('/api/complaints', { params: filters });
return response.data;
}
// Usage
const complaints = await complaintService.getFiltered({
status: 'Open',
priority: 'High',
search: 'pothole'
});- AuthService with token management
- ComplaintService created
- Service hooks created
- Error handling configured
- Interceptors configured
- Replace MOCK_USER with real user from auth
- Replace MOCK_COMPLAINTS with API call
- Replace MOCK_NOTIFICATIONS with API call
- Add loading states
- Add error handling
- ComplaintsListPage: Fetch from API
- ComplaintDetailPage: Fetch from API
- NewComplaintPage: Create via API
- Add form validation
- Add success/error messages
- RTI Service integration
- Land Records Service integration
- Contract Service integration
- Notifications Service integration
- Development without backend
- Placeholder images
- Testing UI components
- Demo mode
- User data in header
- Complaints list
- Statistics/counts
- Notifications
- User profile
cd backend/
python main.py
# Backend runs on localhost:8000// .env or src/services/config.ts
VITE_API_BASE_URL=http://localhost:8000http://localhost:3000/login
β Use real credentials from backend
http://localhost:3000/dashboard
β Should load real data
// src/services/axios.service.ts
axiosInstance.interceptors.request.use(config => {
console.log('API Request:', config.url, config.params);
return config;
});- Open browser DevTools
- Go to Network tab
- Look for API requests
- Check response status and data
401 Unauthorized
- Token expired or invalid
- Check localStorage for 'user_data'
- Try logging in again
404 Not Found
- Wrong endpoint URL
- Check API_ENDPOINTS config
- Verify backend routes exist
CORS Error
- Backend needs CORS headers
- Check FastAPI CORS configuration
- Verify API URL in frontend config
Dashboard Components
β
useComplaintsService() hook
β
ComplaintService class
β
Axios Instance (with interceptors)
β
API Endpoints
β
Backend (FastAPI)
β
Database (PostgreSQL)
Once API integration complete:
- Add pagination for large datasets
- Implement infinite scroll
- Add real-time updates via WebSocket
- Add data caching/optimization
- Add offline capability
- Add sync when online
Q: Can I test without backend running? A: Yes, keep using mock data in mock.data.ts
Q: How do I switch between mock and real? A: Use environment variables or feature flags
Q: What if API is slow? A: Add loading states and error boundaries
Q: How to handle API errors? A: Use try-catch, show error messages to user
Ready to Connect to Backend!
Follow the steps above to replace mock data with real API calls.
For questions, check the service documentation or backend API docs.