fix: improve error handling in admin trades fetch functions

- Return errors from fetch functions instead of setting state directly
- Clear error state before starting a new fetch
- Combine errors when both upcoming and past trades fail to load
- Handle fetch errors in handleAction as well
This commit is contained in:
counterweight 2025-12-23 12:25:15 +01:00
parent e8d0ee2eca
commit 06ad7fefe1
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C

View file

@ -45,17 +45,18 @@ export default function AdminTradesPage() {
const [statusFilter, setStatusFilter] = useState<string>("all"); const [statusFilter, setStatusFilter] = useState<string>("all");
const [userSearch, setUserSearch] = useState(""); const [userSearch, setUserSearch] = useState("");
const fetchUpcomingTrades = useCallback(async () => { const fetchUpcomingTrades = useCallback(async (): Promise<string | null> => {
try { try {
const data = await api.get<AdminExchangeResponse[]>("/api/admin/trades/upcoming"); const data = await api.get<AdminExchangeResponse[]>("/api/admin/trades/upcoming");
setUpcomingTrades(data); setUpcomingTrades(data);
return null;
} catch (err) { } catch (err) {
console.error("Failed to fetch upcoming trades:", err); console.error("Failed to fetch upcoming trades:", err);
setError("Failed to load upcoming trades"); return "Failed to load upcoming trades";
} }
}, []); }, []);
const fetchPastTrades = useCallback(async () => { const fetchPastTrades = useCallback(async (): Promise<string | null> => {
try { try {
let url = "/api/admin/trades/past"; let url = "/api/admin/trades/past";
const params = new URLSearchParams(); const params = new URLSearchParams();
@ -73,16 +74,26 @@ export default function AdminTradesPage() {
const data = await api.get<AdminExchangeResponse[]>(url); const data = await api.get<AdminExchangeResponse[]>(url);
setPastTrades(data); setPastTrades(data);
return null;
} catch (err) { } catch (err) {
console.error("Failed to fetch past trades:", err); console.error("Failed to fetch past trades:", err);
setError("Failed to load past trades"); return "Failed to load past trades";
} }
}, [statusFilter, userSearch]); }, [statusFilter, userSearch]);
useEffect(() => { useEffect(() => {
if (user && isAuthorized) { if (user && isAuthorized) {
setIsLoadingTrades(true); setIsLoadingTrades(true);
Promise.all([fetchUpcomingTrades(), fetchPastTrades()]).finally(() => { setError(null);
Promise.all([fetchUpcomingTrades(), fetchPastTrades()])
.then(([upcomingErr, pastErr]) => {
// Combine errors if both failed
const errors = [upcomingErr, pastErr].filter(Boolean);
if (errors.length > 0) {
setError(errors.join("; "));
}
})
.finally(() => {
setIsLoadingTrades(false); setIsLoadingTrades(false);
}); });
} }
@ -99,7 +110,12 @@ export default function AdminTradesPage() {
: `/api/admin/trades/${tradeId}/${action}`; : `/api/admin/trades/${tradeId}/${action}`;
await api.post<AdminExchangeResponse>(endpoint, {}); await api.post<AdminExchangeResponse>(endpoint, {});
await Promise.all([fetchUpcomingTrades(), fetchPastTrades()]); // Refetch trades - errors from fetch are informational, not critical
const [upcomingErr, pastErr] = await Promise.all([fetchUpcomingTrades(), fetchPastTrades()]);
const fetchErrors = [upcomingErr, pastErr].filter(Boolean);
if (fetchErrors.length > 0) {
setError(fetchErrors.join("; "));
}
setConfirmAction(null); setConfirmAction(null);
} catch (err) { } catch (err) {
setError(err instanceof Error ? err.message : `Failed to ${action} trade`); setError(err instanceof Error ? err.message : `Failed to ${action} trade`);