import { useEffect, useState } from "react"; import { apiClient, ApiError } from "../api/client"; import { MAX_COLD_START_RETRIES, getRetryDelay } from "../utils/retry"; interface CaseSelectorProps { selectedCase: string | null; onSelectCase: (caseId: string) => void; } export function CaseSelector({ selectedCase, onSelectCase, }: CaseSelectorProps) { const [cases, setCases] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [retryCount, setRetryCount] = useState(0); const [isWakingUp, setIsWakingUp] = useState(false); // Fetch cases on mount with cold-start retry logic // Using inline async function pattern recommended by React docs for data fetching useEffect(() => { let isActive = true; const abortController = new AbortController(); async function fetchCases() { let attempts = 0; while (attempts <= MAX_COLD_START_RETRIES && isActive) { try { const data = await apiClient.getCases(abortController.signal); if (!isActive) return; setCases(data.cases); setIsWakingUp(false); setRetryCount(0); setIsLoading(false); return; // Success } catch (err) { if (!isActive) return; if (err instanceof Error && err.name === "AbortError") return; const is503 = err instanceof ApiError && err.status === 503; const isNetworkError = err instanceof TypeError && err.message.toLowerCase().includes("fetch"); // Retry on cold start (503) or network errors if ((is503 || isNetworkError) && attempts < MAX_COLD_START_RETRIES) { attempts++; setRetryCount(attempts); setIsWakingUp(true); // Exponential backoff with capped maximum await new Promise((resolve) => setTimeout(resolve, getRetryDelay(attempts)), ); continue; } // Max retries exceeded or non-retryable error const message = is503 || isNetworkError ? "Backend failed to wake up. Please refresh the page." : err instanceof Error ? err.message : "Unknown error"; setError(`Failed to load cases: ${message}`); setIsWakingUp(false); setIsLoading(false); return; } } } fetchCases(); return () => { isActive = false; abortController.abort(); }; }, []); if (isLoading) { return (
{isWakingUp ? (

Backend waking up... Retry {retryCount}/{MAX_COLD_START_RETRIES}

) : (

Loading cases...

)}
); } if (error) { return (

{error}

); } return (
); }