fix: Remove double .data access in dashboard hooks causing undefined data

CRITICAL BUG FIX: This was the ACTUAL root cause of infinite loading state!

The Bug:
--------
apiClient.get() already returns response.data (line 494 in apiClient.ts):
```typescript
async get<T>(url: string): Promise<T> {
  const response = await this.client.get(url);
  return response.data;  // Returns data directly
}
```

But hooks were doing:
```typescript
queryFn: async () => {
  const response = await apiClient.get('/endpoint');
  return response.data;  // Bug! Accessing .data on data = undefined
}
```

Flow of the Bug:
----------------
1. API call succeeds with 200 OK
2. apiClient.get() returns: {status: "green", headline: "..."}
3. Hook tries to access .data on that object
4. Returns undefined to React Query
5. Component checks: if (!healthStatus) → true (because undefined)
6. Shows skeleton loader forever

The Fix:
--------
Changed all 5 hooks to:
```typescript
queryFn: async () => {
  return await apiClient.get('/endpoint');  //  Returns data directly
}
```

Now:
1. API call succeeds with 200 OK
2. apiClient.get() returns: {status: "green", headline: "..."}
3. Hook returns data to React Query
4. React Query sets data
5. Component receives data → exits loading state
6. Dashboard renders! 🎉

Fixed hooks:
- useBakeryHealthStatus
- useOrchestrationSummary
- useActionQueue
- useProductionTimeline
- useInsights

Previous fixes that were needed but insufficient:
- Added enabled: !!tenantId (prevented queries when tenantId empty)
- Added useTenantInitializer (populated tenantId)
- But data was still undefined due to this .data bug!
This commit is contained in:
Claude
2025-11-07 22:45:23 +00:00
parent f58885911f
commit cfd5585f9d

View File

@@ -152,10 +152,9 @@ export function useBakeryHealthStatus(tenantId: string) {
return useQuery<BakeryHealthStatus>({ return useQuery<BakeryHealthStatus>({
queryKey: ['bakery-health-status', tenantId], queryKey: ['bakery-health-status', tenantId],
queryFn: async () => { queryFn: async () => {
const response = await apiClient.get( return await apiClient.get(
`/tenants/${tenantId}/dashboard/health-status` `/tenants/${tenantId}/dashboard/health-status`
); );
return response.data;
}, },
enabled: !!tenantId, // Only fetch when tenantId is available enabled: !!tenantId, // Only fetch when tenantId is available
refetchInterval: 30000, // Refresh every 30 seconds refetchInterval: 30000, // Refresh every 30 seconds
@@ -174,11 +173,10 @@ export function useOrchestrationSummary(tenantId: string, runId?: string) {
queryKey: ['orchestration-summary', tenantId, runId], queryKey: ['orchestration-summary', tenantId, runId],
queryFn: async () => { queryFn: async () => {
const params = runId ? { run_id: runId } : {}; const params = runId ? { run_id: runId } : {};
const response = await apiClient.get( return await apiClient.get(
`/tenants/${tenantId}/dashboard/orchestration-summary`, `/tenants/${tenantId}/dashboard/orchestration-summary`,
{ params } { params }
); );
return response.data;
}, },
enabled: !!tenantId, // Only fetch when tenantId is available enabled: !!tenantId, // Only fetch when tenantId is available
staleTime: 60000, // Summary doesn't change often staleTime: 60000, // Summary doesn't change often
@@ -196,10 +194,9 @@ export function useActionQueue(tenantId: string) {
return useQuery<ActionQueue>({ return useQuery<ActionQueue>({
queryKey: ['action-queue', tenantId], queryKey: ['action-queue', tenantId],
queryFn: async () => { queryFn: async () => {
const response = await apiClient.get( return await apiClient.get(
`/tenants/${tenantId}/dashboard/action-queue` `/tenants/${tenantId}/dashboard/action-queue`
); );
return response.data;
}, },
enabled: !!tenantId, // Only fetch when tenantId is available enabled: !!tenantId, // Only fetch when tenantId is available
refetchInterval: 60000, // Refresh every minute refetchInterval: 60000, // Refresh every minute
@@ -217,10 +214,9 @@ export function useProductionTimeline(tenantId: string) {
return useQuery<ProductionTimeline>({ return useQuery<ProductionTimeline>({
queryKey: ['production-timeline', tenantId], queryKey: ['production-timeline', tenantId],
queryFn: async () => { queryFn: async () => {
const response = await apiClient.get( return await apiClient.get(
`/tenants/${tenantId}/dashboard/production-timeline` `/tenants/${tenantId}/dashboard/production-timeline`
); );
return response.data;
}, },
enabled: !!tenantId, // Only fetch when tenantId is available enabled: !!tenantId, // Only fetch when tenantId is available
refetchInterval: 60000, // Refresh every minute refetchInterval: 60000, // Refresh every minute
@@ -238,10 +234,9 @@ export function useInsights(tenantId: string) {
return useQuery<Insights>({ return useQuery<Insights>({
queryKey: ['dashboard-insights', tenantId], queryKey: ['dashboard-insights', tenantId],
queryFn: async () => { queryFn: async () => {
const response = await apiClient.get( return await apiClient.get(
`/tenants/${tenantId}/dashboard/insights` `/tenants/${tenantId}/dashboard/insights`
); );
return response.data;
}, },
enabled: !!tenantId, // Only fetch when tenantId is available enabled: !!tenantId, // Only fetch when tenantId is available
refetchInterval: 120000, // Refresh every 2 minutes refetchInterval: 120000, // Refresh every 2 minutes