Skip to content

Latest commit

Β 

History

History
451 lines (346 loc) Β· 10.1 KB

File metadata and controls

451 lines (346 loc) Β· 10.1 KB

Dashboard Integration Guide - Backend API Connection

πŸ”— Connecting Dashboard to Backend Services

This guide explains how to replace mock data with real backend API calls.

πŸ“Œ Current State

  • βœ… Dashboard UI fully created
  • βœ… Mock data implemented
  • ⏳ Ready for service integration
  • ⏳ Services created (auth, complaint, etc.)

πŸ”„ Integration Steps

Step 1: Update Complaint List Page

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
}

Step 2: Update Dashboard Page

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
}

Step 3: Update New Complaint Form

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);
    }
  }
}

Step 4: Update Complaint Detail Page

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
  );
}

πŸ“‹ Service Methods to Implement

ComplaintService

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[]>;
}

RTIService

interface IRTIService {
  getAll(): Promise<RTIRequest[]>;
  getById(id: number): Promise<RTIRequest>;
  create(data: CreateRTIRequest): Promise<RTIRequest>;
  update(id: number, data: UpdateRTIRequest): Promise<RTIRequest>;
}

LandRecordService

interface ILandRecordService {
  getAll(): Promise<LandRecord[]>;
  getById(id: number): Promise<LandRecord>;
  verify(id: number): Promise<LandRecord>;
}

🎯 Data Flow

Current (Mock)

Component β†’ useState β†’ MOCK_DATA β†’ Render

After Integration (Real API)

Component β†’ useService β†’ Axios β†’ Backend API β†’ useState β†’ Render

πŸ“Š Example: Full Integration Flow

1. User logs in

LoginForm β†’ authService.login() β†’ API β†’ Token stored β†’ Redirect to /dashboard

2. Dashboard loads

DashboardPage β†’ useComplaintsService.getAll() β†’ API (with auth header) β†’ MOCK_COMPLAINTS replaced β†’ Render

3. User files complaint

NewComplaintForm β†’ complaintService.create(data) β†’ API β†’ Complaint created β†’ Redirect to list

4. User views details

ComplaintDetailPage β†’ complaintService.getById(id) β†’ API β†’ Render with real data

πŸ” Authentication Integration

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 automatically

πŸ“ Backend Endpoint Mapping

Replace 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',
};

πŸ” Filtering & Searching

Mock Implementation

// Current: Done in-component
const filtered = complaints.filter(c => c.status === filterStatus);

Backend Implementation

// 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'
});

πŸš€ Implementation Checklist

Phase 1: Services Ready

  • AuthService with token management
  • ComplaintService created
  • Service hooks created
  • Error handling configured
  • Interceptors configured

Phase 2: Dashboard Integration

  • 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

Phase 3: Pages Integration

  • ComplaintsListPage: Fetch from API
  • ComplaintDetailPage: Fetch from API
  • NewComplaintPage: Create via API
  • Add form validation
  • Add success/error messages

Phase 4: Additional Services

  • RTI Service integration
  • Land Records Service integration
  • Contract Service integration
  • Notifications Service integration

πŸ’Ύ Mock to Real Transition Strategy

Keep Mock Data For:

  1. Development without backend
  2. Placeholder images
  3. Testing UI components
  4. Demo mode

Replace with API For:

  1. User data in header
  2. Complaints list
  3. Statistics/counts
  4. Notifications
  5. User profile

πŸ§ͺ Testing with Real API

1. Start Backend

cd backend/
python main.py
# Backend runs on localhost:8000

2. Update API URL if needed

// .env or src/services/config.ts
VITE_API_BASE_URL=http://localhost:8000

3. Test login first

http://localhost:3000/login
β†’ Use real credentials from backend

4. Test dashboard

http://localhost:3000/dashboard
β†’ Should load real data

πŸ› Debugging API Integration

Enable API Logging

// src/services/axios.service.ts
axiosInstance.interceptors.request.use(config => {
  console.log('API Request:', config.url, config.params);
  return config;
});

Check Network Tab

  1. Open browser DevTools
  2. Go to Network tab
  3. Look for API requests
  4. Check response status and data

Common Issues

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

πŸ“š Service Layer Architecture

Dashboard Components
        ↓
useComplaintsService() hook
        ↓
ComplaintService class
        ↓
Axios Instance (with interceptors)
        ↓
API Endpoints
        ↓
Backend (FastAPI)
        ↓
Database (PostgreSQL)

βœ… Future Enhancements

Once API integration complete:

  1. Add pagination for large datasets
  2. Implement infinite scroll
  3. Add real-time updates via WebSocket
  4. Add data caching/optimization
  5. Add offline capability
  6. Add sync when online

πŸ“ž Common Questions

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.