Skip to content

Commit 8ae142e

Browse files
committed
fix: stop admin overview auto-refresh loop on 500 errors and harden endpoint
1 parent c4a43e9 commit 8ae142e

2 files changed

Lines changed: 52 additions & 28 deletions

File tree

client/src/pages/admin/overview.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
88
export default function AdminOverview() {
99
const [range, setRange] = useState("7d");
1010

11-
const { data: metrics, isLoading } = useQuery<any>({
11+
const { data: metrics, isLoading, isError, error } = useQuery<any>({
1212
queryKey: [`/api/admin/overview?range=${range}`],
13-
refetchInterval: 2000,
13+
refetchInterval: 30000,
14+
retry: 2,
15+
refetchIntervalInBackground: false,
1416
});
1517

1618
if (isLoading) {
@@ -21,6 +23,17 @@ export default function AdminOverview() {
2123
);
2224
}
2325

26+
if (isError) {
27+
return (
28+
<div className="flex h-[50vh] items-center justify-center">
29+
<div className="text-center space-y-2">
30+
<p className="text-sm text-destructive font-medium">Failed to load admin overview</p>
31+
<p className="text-xs text-muted-foreground">{(error as any)?.message || "An unexpected error occurred"}</p>
32+
</div>
33+
</div>
34+
);
35+
}
36+
2437
const growthData = metrics?.growthMetrics || [];
2538

2639
return (

server/routes/admin.ts

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -149,32 +149,42 @@ router.get("/overview", async (req, res) => {
149149
const [{ count: totalAudits }] = await db.select({ count: sql<number>`count(*)` }).from(audits);
150150
const [{ count: totalOrders }] = await db.select({ count: sql<number>`count(*)` }).from(auditOrders);
151151

152-
// Calculate total API cost
153-
const [{ totalCost }] = await db.select({ totalCost: sql<number>`sum(CAST(cost_usd AS float))` }).from(apiUsageLog);
152+
// Calculate total API cost — handle empty table gracefully
153+
let totalCost = 0;
154+
try {
155+
const [costRow] = await db.select({ totalCost: sql<number>`COALESCE(sum(CAST(cost_usd AS float)), 0)` }).from(apiUsageLog);
156+
totalCost = Number(costRow?.totalCost || 0);
157+
} catch { /* table may be empty */ }
154158

155159
// Feedback metrics
156-
const [{ count: feedbackCount }] = await db.select({ count: sql<number>`count(*)` }).from(auditFeedback).where(isNotNull(auditFeedback.respondedAt));
157-
const feedbackRows = await db.select().from(auditFeedback).where(isNotNull(auditFeedback.respondedAt));
158-
159-
let totalAccuracy = 0;
160-
let totalValue = 0;
161-
let validAccuracy = 0;
162-
let validValue = 0;
163-
164-
feedbackRows.forEach(f => {
165-
const responses = f.responses as any;
166-
if (responses?.accuracy) {
167-
totalAccuracy += Number(responses.accuracy);
168-
validAccuracy++;
169-
}
170-
if (responses?.willingnessToPay) {
171-
totalValue += Number(responses.willingnessToPay);
172-
validValue++;
173-
}
174-
});
175-
176-
const avgAccuracy = validAccuracy > 0 ? (totalAccuracy / validAccuracy).toFixed(1) : "0.0";
177-
const avgValue = validValue > 0 ? (totalValue / validValue).toFixed(1) : "0.0";
160+
let feedbackCount = 0;
161+
let avgAccuracy = "0.0";
162+
let avgValue = "0.0";
163+
try {
164+
const [{ count: fbCount }] = await db.select({ count: sql<number>`count(*)` }).from(auditFeedback).where(isNotNull(auditFeedback.respondedAt));
165+
feedbackCount = Number(fbCount);
166+
const feedbackRows = await db.select().from(auditFeedback).where(isNotNull(auditFeedback.respondedAt));
167+
168+
let totalAccuracy = 0;
169+
let totalValue = 0;
170+
let validAccuracy = 0;
171+
let validValue = 0;
172+
173+
feedbackRows.forEach(f => {
174+
const responses = f.responses as any;
175+
if (responses?.accuracy) {
176+
totalAccuracy += Number(responses.accuracy);
177+
validAccuracy++;
178+
}
179+
if (responses?.willingnessToPay) {
180+
totalValue += Number(responses.willingnessToPay);
181+
validValue++;
182+
}
183+
});
184+
185+
avgAccuracy = validAccuracy > 0 ? (totalAccuracy / validAccuracy).toFixed(1) : "0.0";
186+
avgValue = validValue > 0 ? (totalValue / validValue).toFixed(1) : "0.0";
187+
} catch { /* feedback table may not exist yet */ }
178188

179189
const rangeParam = req.query.range as string || "7d";
180190
const startDate = new Date();
@@ -228,15 +238,16 @@ router.get("/overview", async (req, res) => {
228238
totalUsers: Number(totalUsers),
229239
totalAudits: Number(totalAudits),
230240
totalOrders: Number(totalOrders),
231-
totalApiCost: Number(totalCost || 0).toFixed(2),
241+
totalApiCost: totalCost.toFixed(2),
232242
growthMetrics,
233243
feedback: {
234-
count: Number(feedbackCount),
244+
count: feedbackCount,
235245
avgAccuracy,
236246
avgValue
237247
}
238248
});
239249
} catch (error: any) {
250+
console.error("[Admin] Overview error:", error);
240251
res.status(500).json({ error: error.message });
241252
}
242253
});

0 commit comments

Comments
 (0)