fix: Comprehensive authentication and UI fixes
Authentication & Token Management: - Add deviceId to token refresh flow (backend requires both refreshToken and deviceId) - Fix React Strict Mode token clearing race condition with retry logic - Improve AuthContext to handle all token state combinations properly - Store deviceId in localStorage alongside tokens UI/UX Improvements: - Remove deprecated legacyBehavior from Next.js Link components - Update primary theme color to WCAG AA compliant #7c3aed - Fix nested button error in TabBar voice navigation - Fix invalid Tabs value error in DynamicChildDashboard Multi-Child Dashboard: - Load all children into Redux store properly - Fetch metrics for all children, not just selected one - Remove mock data to prevent unauthorized API calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,7 @@ export default function HomePage() {
|
||||
const [children, setChildren] = useState<Child[]>([]);
|
||||
const [recentActivities, setRecentActivities] = useState<any[]>([]);
|
||||
const [todaySummary, setTodaySummary] = useState<any>(null);
|
||||
const [allChildMetrics, setAllChildMetrics] = useState<any>({});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<any>(null);
|
||||
|
||||
@@ -58,10 +59,21 @@ export default function HomePage() {
|
||||
}, [familyId, authLoading]);
|
||||
|
||||
const loadChildren = async () => {
|
||||
if (!familyId) return;
|
||||
if (!familyId) {
|
||||
console.warn('[HomePage] No familyId available, cannot load children');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('[HomePage] Loading children for familyId:', familyId);
|
||||
|
||||
// Dispatch to Redux to load children into store
|
||||
await dispatch(fetchChildren(familyId)).unwrap();
|
||||
|
||||
// Also get children for local state
|
||||
const data = await childrenApi.getChildren(familyId);
|
||||
console.log('[HomePage] Loaded children:', data.map(c => ({ id: c.id, name: c.name, familyId: c.familyId })));
|
||||
|
||||
setChildren(data);
|
||||
if (data.length > 0 && !selectedChildId) {
|
||||
setSelectedChildId(data[0].id);
|
||||
@@ -72,48 +84,68 @@ export default function HomePage() {
|
||||
}
|
||||
};
|
||||
|
||||
// Load dashboard data when child selected
|
||||
// Load dashboard data when children are loaded
|
||||
useEffect(() => {
|
||||
if (selectedChildId) {
|
||||
if (children.length > 0) {
|
||||
loadDashboardData();
|
||||
}
|
||||
}, [selectedChildId]);
|
||||
}, [children]);
|
||||
|
||||
const loadDashboardData = async () => {
|
||||
if (!selectedChildId) return;
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
// Load recent activities
|
||||
const activities = await trackingApi.getActivities(selectedChildId);
|
||||
setRecentActivities(activities.slice(0, 10));
|
||||
// Load activities for ALL children to populate metrics
|
||||
const allMetrics: any = {};
|
||||
|
||||
// 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;
|
||||
});
|
||||
for (const child of children) {
|
||||
try {
|
||||
const activities = await trackingApi.getActivities(child.id);
|
||||
|
||||
const summary = {
|
||||
feedingCount: todayActivities.filter((a: any) => a.type === 'feeding').length,
|
||||
sleepCount: todayActivities.filter((a: any) => a.type === 'sleep').length,
|
||||
diaperCount: todayActivities.filter((a: any) => a.type === 'diaper').length,
|
||||
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),
|
||||
};
|
||||
// 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;
|
||||
});
|
||||
|
||||
setTodaySummary(summary);
|
||||
allMetrics[child.id] = {
|
||||
feedingCount: todayActivities.filter((a: any) => a.type === 'feeding').length,
|
||||
sleepCount: todayActivities.filter((a: any) => a.type === 'sleep').length,
|
||||
diaperCount: todayActivities.filter((a: any) => a.type === 'diaper').length,
|
||||
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 || a.metadata?.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),
|
||||
};
|
||||
|
||||
// If this is the selected child, also set recent activities
|
||||
if (child.id === selectedChildId) {
|
||||
setRecentActivities(activities.slice(0, 10));
|
||||
setTodaySummary(allMetrics[child.id]);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Failed to load activities for child ${child.id}:`, err);
|
||||
allMetrics[child.id] = {
|
||||
feedingCount: 0,
|
||||
sleepCount: 0,
|
||||
diaperCount: 0,
|
||||
medicationCount: 0,
|
||||
totalFeedingAmount: 0,
|
||||
totalSleepDuration: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Store all metrics in state
|
||||
setAllChildMetrics(allMetrics);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
console.error('Failed to load dashboard data:', err);
|
||||
@@ -188,15 +220,15 @@ export default function HomePage() {
|
||||
|
||||
const isLoading = authLoading || loading;
|
||||
|
||||
// Build child metrics object for DynamicChildDashboard
|
||||
// Build child metrics object for DynamicChildDashboard from allChildMetrics
|
||||
const childMetrics = children.reduce((acc: any, child: any) => {
|
||||
// Use todaySummary for selected child, or zero for others
|
||||
if (child.id === selectedChildId && todaySummary) {
|
||||
const metrics = allChildMetrics[child.id];
|
||||
if (metrics) {
|
||||
acc[child.id] = {
|
||||
feedingCount: todaySummary.feedingCount || 0,
|
||||
sleepDuration: todaySummary.totalSleepDuration || 0,
|
||||
diaperCount: todaySummary.diaperCount || 0,
|
||||
medicationCount: todaySummary.medicationCount || 0,
|
||||
feedingCount: metrics.feedingCount || 0,
|
||||
sleepDuration: metrics.totalSleepDuration || 0,
|
||||
diaperCount: metrics.diaperCount || 0,
|
||||
medicationCount: metrics.medicationCount || 0,
|
||||
};
|
||||
} else {
|
||||
acc[child.id] = {
|
||||
|
||||
Reference in New Issue
Block a user