Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion frontend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
# Copy this file to .env and fill in your values

# API Configuration
VITE_API_URL=http://localhost:8000
# IMPORTANT: Must include /api/v1 path to properly connect to backend
VITE_API_URL=http://localhost:8000/api/v1

# App Version (for Sentry releases)
VITE_APP_VERSION=1.0.0
Expand Down
58 changes: 58 additions & 0 deletions frontend/CASES_PAGE_FIX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Cases Page Launch Issue Fix

## Problem
The cases page was failing to launch because API calls were not reaching the backend server.

## Root Cause
The `apiRequest` function in `src/lib/api.ts` was not prepending the base API URL to relative URLs. This caused requests like `/cases?page=1` to be sent to the frontend server (http://localhost:5173) instead of the backend API server (http://localhost:8000/api/v1).

## Solution
1. **Updated `apiRequest` function** to prepend `VITE_API_URL` for relative URLs
2. **Updated `.env.example`** to show correct API URL including `/api/v1` path

## Setup Instructions

### 1. Create .env file
```bash
cp .env.example .env
```

### 2. Verify API URL in .env
```env
VITE_API_URL=http://localhost:8000/api/v1
```

**Important:** The `/api/v1` path is required. Do not use just `http://localhost:8000`.

### 3. Start servers
```bash
# Terminal 1 - Backend
cd backend
# ... start backend server on port 8000

# Terminal 2 - Frontend
cd frontend
npm install
npm run dev
```

### 4. Test
Navigate to http://localhost:5173/cases - the page should now load successfully and fetch case data from the backend.

## Files Changed
- `src/lib/api.ts` - Fixed `apiRequest` to prepend BASE_URL
- `.env.example` - Updated with correct API URL

## Affected Components
This fix resolves API issues for ALL components using `apiRequest`:
- CaseList, CaseDetail
- Forensics, FinalSummary, Ingestion, AdjudicationQueue
- All adjudication components
- Evidence API
- And more...

## Production Deployment
For production, update `VITE_API_URL` to point to your production API server:
```env
VITE_API_URL=https://api.your-domain.com/api/v1
```
6 changes: 5 additions & 1 deletion frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export async function apiRequest<T = any>(
): Promise<T> {
const method = options?.method?.toUpperCase() || 'GET';

// Prepend base URL if URL is relative
const BASE_URL = import.meta.env.VITE_API_URL || '/api/v1';
const fullUrl = url.startsWith('http') ? url : `${BASE_URL}${url}`;

// Prepare headers
const headers = new Headers(options?.headers);
if (!headers.has('Content-Type')) {
Expand Down Expand Up @@ -66,7 +70,7 @@ export async function apiRequest<T = any>(
requestOptions.body = options.body;
}

const response = await fetch(url, requestOptions);
const response = await fetch(fullUrl, requestOptions);

if (!response.ok) {
await response.text().catch(() => 'Unknown error');
Comment on lines 75 to 76
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Include API error body in exception

New proposed code:
 if (!response.ok) {
-  await response.text().catch(() => 'Unknown error');
-  throw new Error(`API request failed: ${response.status} ${response.statusText}`);
+  const errorBody = await response.text().catch(() => 'Could not read error body');
+  throw new Error(`API request failed: ${response.status} ${response.statusText} - ${errorBody}`);
 }

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/CaseDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ interface PredictiveResponse {

const { data: aiRiskPrediction, isLoading: predictionLoading } = useQuery({
queryKey: ['case', id, 'ai-risk-prediction'],
queryFn: () => apiRequest<PredictiveResponse>(`/cases/${id}/ai-risk-prediction`),
queryFn: () => apiRequest<PredictiveResponse>(`/cases/${id}/ai-risk-prediction`, { method: 'POST' }),
retry: false,
enabled: !!id,
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/CaseList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function CaseList() {
else if (riskFilter === 'low') params.append('max_risk', '39');
}

return apiRequest<CaseListResponse>('/cases/?' + params.toString());
return apiRequest<CaseListResponse>(`/cases?${params.toString()}`);
};

const { data, isLoading, error, refetch } = useQuery({
Expand Down
Loading