Skip to content

Commit d4e19ff

Browse files
committed
feat: enhance DashboardPage with dynamic API base URL configuration and health check; implement fallback API endpoints and display connection status
1 parent ab4912c commit d4e19ff

1 file changed

Lines changed: 143 additions & 12 deletions

File tree

frontend/src/pages/DashboardPage.jsx

Lines changed: 143 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,28 @@ import ProtectedRoute from '../components/ProtectedRoute';
55
import * as XLSX from 'xlsx';
66
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid, LabelList, ReferenceLine, Legend, Cell } from 'recharts';
77

8-
const API_BASE = import.meta.env.VITE_API_BASE || 'http://127.0.0.1:8000';
8+
// API Base URL configuration
9+
const getApiBase = () => {
10+
// Check for environment variable first
11+
const envApiBase = import.meta.env.VITE_API_BASE;
12+
13+
// If environment variable is set and doesn't look like a frontend URL, use it
14+
if (envApiBase && !envApiBase.includes('azurestaticapps.net')) {
15+
return envApiBase;
16+
}
17+
18+
// Default to the Azure backend API
19+
return 'https://hospital-readmission-backend-api-e5fsevbxggfhdxbr.southindia-01.azurewebsites.net';
20+
};
21+
22+
const API_BASE = getApiBase();
23+
24+
// Fallback API URLs in case the primary one fails
25+
const FALLBACK_APIS = [
26+
'https://hospital-readmission-backend-api-e5fsevbxggfhdxbr.southindia-01.azurewebsites.net',
27+
'http://127.0.0.1:8000',
28+
'http://localhost:8000'
29+
];
930

1031
const DIAG_OPTIONS = [
1132
{ value: '', label: 'Select diagnosis' },
@@ -80,9 +101,35 @@ const DashboardPage = () => {
80101
readmitted: ''
81102
});
82103
const [manualError, setManualError] = useState('');
104+
const [apiStatus, setApiStatus] = useState({ connected: false, endpoint: '', checking: true });
83105

84106
const acceptedExtensions = useMemo(() => ['.xls', '.xlsx'], []);
85107

108+
// Check API status on component mount
109+
React.useEffect(() => {
110+
const checkApiStatus = async () => {
111+
setApiStatus({ connected: false, endpoint: '', checking: true });
112+
113+
const apiUrls = [API_BASE, ...FALLBACK_APIS.filter(url => url !== API_BASE)];
114+
115+
for (const baseUrl of apiUrls) {
116+
try {
117+
const isHealthy = await checkApiHealth(baseUrl);
118+
if (isHealthy) {
119+
setApiStatus({ connected: true, endpoint: baseUrl, checking: false });
120+
return;
121+
}
122+
} catch (error) {
123+
console.error(`API status check failed for ${baseUrl}:`, error);
124+
}
125+
}
126+
127+
setApiStatus({ connected: false, endpoint: '', checking: false });
128+
};
129+
130+
checkApiStatus();
131+
}, []);
132+
86133
const handleBrowseClick = () => {
87134
fileInputRef.current?.click();
88135
};
@@ -161,17 +208,54 @@ const DashboardPage = () => {
161208
};
162209
};
163210

211+
const checkApiHealth = async (baseUrl) => {
212+
try {
213+
const res = await fetch(`${baseUrl}/health`);
214+
return res.ok;
215+
} catch (error) {
216+
console.error(`API health check failed for ${baseUrl}:`, error);
217+
return false;
218+
}
219+
};
220+
164221
const callExplain = async (patient) => {
165-
const res = await fetch(`${API_BASE}/explain`, {
166-
method: 'POST',
167-
headers: { 'Content-Type': 'application/json' },
168-
body: JSON.stringify(patient)
169-
});
170-
if (!res.ok) {
171-
const err = await res.json().catch(() => ({}));
172-
throw new Error(err.detail || `HTTP ${res.status}`);
222+
// Try multiple API endpoints
223+
const apiUrls = [API_BASE, ...FALLBACK_APIS.filter(url => url !== API_BASE)];
224+
225+
for (const baseUrl of apiUrls) {
226+
try {
227+
console.log('Trying API with URL:', `${baseUrl}/explain`);
228+
229+
// First check if API is accessible
230+
const isHealthy = await checkApiHealth(baseUrl);
231+
if (!isHealthy) {
232+
console.log(`API at ${baseUrl} is not healthy, trying next...`);
233+
continue;
234+
}
235+
236+
const res = await fetch(`${baseUrl}/explain`, {
237+
method: 'POST',
238+
headers: { 'Content-Type': 'application/json' },
239+
body: JSON.stringify(patient)
240+
});
241+
242+
if (!res.ok) {
243+
const err = await res.json().catch(() => ({}));
244+
console.error('API Error:', res.status, res.statusText, err);
245+
throw new Error(err.detail || `HTTP ${res.status}: ${res.statusText}`);
246+
}
247+
248+
console.log(`Successfully called API at ${baseUrl}`);
249+
return res.json();
250+
} catch (error) {
251+
console.error(`Failed to call API at ${baseUrl}:`, error);
252+
// Continue to next API if this one fails
253+
continue;
254+
}
173255
}
174-
return res.json();
256+
257+
// If all APIs fail, throw an error
258+
throw new Error('All API endpoints are unreachable. Please check your network connection and backend service status.');
175259
};
176260

177261
const processFile = useCallback(async (file) => {
@@ -334,10 +418,57 @@ const DashboardPage = () => {
334418
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
335419
{/* Header */}
336420
<div className="mb-8">
337-
<h1 className="text-3xl font-bold text-gray-900 mb-2">Dashboard</h1>
338-
<p className="text-gray-600">Welcome back, {user?.email || 'User'}!</p>
421+
<div className="flex items-center justify-between">
422+
<div>
423+
<h1 className="text-3xl font-bold text-gray-900 mb-2">Dashboard</h1>
424+
<p className="text-gray-600">Welcome back, {user?.email || 'User'}!</p>
425+
</div>
426+
<div className="flex items-center gap-2">
427+
{apiStatus.checking ? (
428+
<div className="flex items-center gap-2 text-yellow-600">
429+
<div className="w-2 h-2 bg-yellow-500 rounded-full animate-pulse"></div>
430+
<span className="text-sm">Checking API...</span>
431+
</div>
432+
) : apiStatus.connected ? (
433+
<div className="flex items-center gap-2 text-green-600">
434+
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
435+
<span className="text-sm">API Connected</span>
436+
</div>
437+
) : (
438+
<div className="flex items-center gap-2 text-red-600">
439+
<div className="w-2 h-2 bg-red-500 rounded-full"></div>
440+
<span className="text-sm">API Disconnected</span>
441+
</div>
442+
)}
443+
</div>
444+
</div>
339445
</div>
340446

447+
{/* API Status Warning */}
448+
{!apiStatus.checking && !apiStatus.connected && (
449+
<div className="bg-red-50 border border-red-200 rounded-lg p-4 mb-6">
450+
<div className="flex items-center">
451+
<div className="flex-shrink-0">
452+
<svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
453+
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
454+
</svg>
455+
</div>
456+
<div className="ml-3">
457+
<h3 className="text-sm font-medium text-red-800">API Connection Issue</h3>
458+
<div className="mt-2 text-sm text-red-700">
459+
<p>The backend API is currently unreachable. This may be due to:</p>
460+
<ul className="list-disc list-inside mt-1 space-y-1">
461+
<li>Backend service is down or restarting</li>
462+
<li>Network connectivity issues</li>
463+
<li>Incorrect API endpoint configuration</li>
464+
</ul>
465+
<p className="mt-2">Please try again later or contact support if the issue persists.</p>
466+
</div>
467+
</div>
468+
</div>
469+
</div>
470+
)}
471+
341472
{/* Uploader */}
342473
<div className="bg-white rounded-xl shadow-sm p-6 border border-gray-200 mb-8">
343474
<div className="flex items-center justify-between mb-4">

0 commit comments

Comments
 (0)