fix: Replace GraphQL with REST API for home page dashboard
GraphQL endpoint was returning 400 errors due to authentication issues with the GqlAuthGuard. Replaced GraphQL query with REST API calls to match the working insights page pattern. Changes: - Removed useQuery(GET_DASHBOARD) GraphQL call - Added REST API calls: childrenApi.getChildren(), trackingApi.getActivities() - Calculate today's summary from activities client-side - Load children and dashboard data separately - Removed all GraphQL debug logging Now home page uses same REST pattern as insights page: 1. Load children via childrenApi 2. Load activities via trackingApi 3. Calculate summary from filtered activities This eliminates the GraphQL 400 errors and makes Today's Summary display correctly with feeding count, sleep duration, diaper count. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -22,8 +22,8 @@ import {
|
|||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { useAuth } from '@/lib/auth/AuthContext';
|
import { useAuth } from '@/lib/auth/AuthContext';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useQuery } from '@apollo/client/react';
|
import { childrenApi, Child } from '@/lib/api/children';
|
||||||
import { GET_DASHBOARD } from '@/graphql/queries/dashboard';
|
import { trackingApi } from '@/lib/api/tracking';
|
||||||
import { format, formatDistanceToNow } from 'date-fns';
|
import { format, formatDistanceToNow } from 'date-fns';
|
||||||
import { useRealTimeActivities } from '@/hooks/useWebSocket';
|
import { useRealTimeActivities } from '@/hooks/useWebSocket';
|
||||||
import { useTranslation } from '@/hooks/useTranslation';
|
import { useTranslation } from '@/hooks/useTranslation';
|
||||||
@@ -44,58 +44,91 @@ export default function HomePage() {
|
|||||||
const [selectedChildId, setSelectedChildId] = useState<string | null>(null);
|
const [selectedChildId, setSelectedChildId] = useState<string | null>(null);
|
||||||
const [predictions, setPredictions] = useState<any>(null);
|
const [predictions, setPredictions] = useState<any>(null);
|
||||||
const [predictionsLoading, setPredictionsLoading] = useState(false);
|
const [predictionsLoading, setPredictionsLoading] = useState(false);
|
||||||
|
const [children, setChildren] = useState<Child[]>([]);
|
||||||
|
const [recentActivities, setRecentActivities] = useState<any[]>([]);
|
||||||
|
const [todaySummary, setTodaySummary] = useState<any>(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState<any>(null);
|
||||||
|
|
||||||
// Fetch children on mount
|
// Load children
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (familyId && !authLoading) {
|
if (familyId && !authLoading) {
|
||||||
dispatch(fetchChildren(familyId));
|
loadChildren();
|
||||||
}
|
}
|
||||||
}, [familyId, authLoading, dispatch]);
|
}, [familyId, authLoading]);
|
||||||
|
|
||||||
// GraphQL query for dashboard data
|
const loadChildren = async () => {
|
||||||
const { data, loading, error, refetch } = useQuery(GET_DASHBOARD, {
|
if (!familyId) return;
|
||||||
variables: { childId: selectedChildId },
|
|
||||||
skip: authLoading || !user,
|
|
||||||
fetchPolicy: 'cache-and-network',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Log GraphQL errors and data for debugging
|
try {
|
||||||
|
const data = await childrenApi.getChildren(familyId);
|
||||||
|
setChildren(data);
|
||||||
|
if (data.length > 0 && !selectedChildId) {
|
||||||
|
setSelectedChildId(data[0].id);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to load children:', err);
|
||||||
|
setError(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load dashboard data when child selected
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('[HomePage] === GraphQL Debug Info ===');
|
if (selectedChildId) {
|
||||||
console.log('[HomePage] Raw data:', data);
|
loadDashboardData();
|
||||||
console.log('[HomePage] Data type:', typeof data);
|
}
|
||||||
console.log('[HomePage] Data keys:', data ? Object.keys(data) : 'null');
|
}, [selectedChildId]);
|
||||||
|
|
||||||
if (error) {
|
const loadDashboardData = async () => {
|
||||||
console.error('[HomePage] GraphQL error:', error);
|
if (!selectedChildId) return;
|
||||||
console.error('[HomePage] GraphQL error details:', {
|
|
||||||
message: error.message,
|
setLoading(true);
|
||||||
networkError: error.networkError,
|
try {
|
||||||
graphQLErrors: error.graphQLErrors,
|
// Load recent activities
|
||||||
|
const activities = await trackingApi.getActivities(selectedChildId);
|
||||||
|
setRecentActivities(activities.slice(0, 10));
|
||||||
|
|
||||||
|
// Calculate today's summary from activities
|
||||||
|
const today = new Date();
|
||||||
|
today.setHours(0, 0, 0, 0);
|
||||||
|
const todayActivities = activities.filter((a: any) => {
|
||||||
|
const activityDate = new Date(a.timestamp || a.startedAt);
|
||||||
|
return activityDate >= today;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
if (data) {
|
|
||||||
console.log('[HomePage] GraphQL data:', data);
|
|
||||||
console.log('[HomePage] Dashboard data:', data.dashboard);
|
|
||||||
}
|
|
||||||
console.log('[HomePage] Query state:', {
|
|
||||||
loading,
|
|
||||||
error: !!error,
|
|
||||||
hasData: !!data,
|
|
||||||
user: !!user,
|
|
||||||
skip: authLoading || !user,
|
|
||||||
childrenCount: data?.dashboard?.children?.length || 0,
|
|
||||||
selectedChildId,
|
|
||||||
});
|
|
||||||
console.log('[HomePage] LocalStorage token:', typeof window !== 'undefined' ? localStorage.getItem('accessToken')?.substring(0, 20) : 'SSR');
|
|
||||||
}, [error, data, loading, user, authLoading, selectedChildId]);
|
|
||||||
|
|
||||||
// Real-time activity handler to refetch dashboard data
|
const summary = {
|
||||||
const refreshDashboard = useCallback(async () => {
|
feedingCount: todayActivities.filter((a: any) => a.type === 'feeding').length,
|
||||||
if (refetch) {
|
sleepCount: todayActivities.filter((a: any) => a.type === 'sleep').length,
|
||||||
console.log('[HomePage] Refreshing dashboard data...');
|
diaperCount: todayActivities.filter((a: any) => a.type === 'diaper').length,
|
||||||
await refetch();
|
medicationCount: todayActivities.filter((a: any) => ['medication', 'medicine'].includes(a.type)).length,
|
||||||
|
totalFeedingAmount: todayActivities
|
||||||
|
.filter((a: any) => a.type === 'feeding')
|
||||||
|
.reduce((sum: number, a: any) => sum + (a.data?.amount || 0), 0),
|
||||||
|
totalSleepDuration: todayActivities
|
||||||
|
.filter((a: any) => a.type === 'sleep')
|
||||||
|
.reduce((sum: number, a: any) => {
|
||||||
|
const start = new Date(a.startedAt);
|
||||||
|
const end = a.endedAt ? new Date(a.endedAt) : new Date();
|
||||||
|
return sum + (end.getTime() - start.getTime()) / (1000 * 60);
|
||||||
|
}, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
setTodaySummary(summary);
|
||||||
|
setError(null);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to load dashboard data:', err);
|
||||||
|
setError(err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const refetch = loadDashboardData;
|
||||||
|
|
||||||
|
// Real-time activity handler
|
||||||
|
const refreshDashboard = useCallback(async () => {
|
||||||
|
console.log('[HomePage] Refreshing dashboard data...');
|
||||||
|
await refetch();
|
||||||
}, [refetch]);
|
}, [refetch]);
|
||||||
|
|
||||||
// Subscribe to real-time activity updates
|
// Subscribe to real-time activity updates
|
||||||
@@ -105,14 +138,6 @@ export default function HomePage() {
|
|||||||
refreshDashboard // On activity deleted
|
refreshDashboard // On activity deleted
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set the first child as selected when data loads
|
|
||||||
useEffect(() => {
|
|
||||||
if (data?.dashboard?.children && data.dashboard.children.length > 0 && !selectedChildId) {
|
|
||||||
const firstChild = data.dashboard.children[0];
|
|
||||||
setSelectedChildId(firstChild.id);
|
|
||||||
}
|
|
||||||
}, [data, selectedChildId]);
|
|
||||||
|
|
||||||
// Sync selectedChildId with Redux selectedChild
|
// Sync selectedChildId with Redux selectedChild
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedChild?.id && selectedChild.id !== selectedChildId) {
|
if (selectedChild?.id && selectedChild.id !== selectedChildId) {
|
||||||
@@ -161,22 +186,17 @@ export default function HomePage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract data from GraphQL response
|
|
||||||
const children = data?.dashboard?.children || [];
|
|
||||||
const graphqlSelectedChild = data?.dashboard?.selectedChild;
|
|
||||||
const dailySummary = data?.dashboard?.todaySummary;
|
|
||||||
const isLoading = authLoading || loading;
|
const isLoading = authLoading || loading;
|
||||||
|
|
||||||
// Build child metrics object for DynamicChildDashboard
|
// Build child metrics object for DynamicChildDashboard
|
||||||
const childMetrics = children.reduce((acc: any, child: any) => {
|
const childMetrics = children.reduce((acc: any, child: any) => {
|
||||||
// For now, use the same summary for selected child, or zero for others
|
// Use todaySummary for selected child, or zero for others
|
||||||
// TODO: Fetch per-child summaries from backend
|
if (child.id === selectedChildId && todaySummary) {
|
||||||
if (child.id === selectedChildId && dailySummary) {
|
|
||||||
acc[child.id] = {
|
acc[child.id] = {
|
||||||
feedingCount: dailySummary.feedingCount || 0,
|
feedingCount: todaySummary.feedingCount || 0,
|
||||||
sleepDuration: dailySummary.totalSleepDuration || 0,
|
sleepDuration: todaySummary.totalSleepDuration || 0,
|
||||||
diaperCount: dailySummary.diaperCount || 0,
|
diaperCount: todaySummary.diaperCount || 0,
|
||||||
medicationCount: dailySummary.medicationCount || 0,
|
medicationCount: todaySummary.medicationCount || 0,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
acc[child.id] = {
|
acc[child.id] = {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user