'use client'; import { useState, useEffect } from 'react'; import { Box, Typography, Grid, Card, CardContent, Select, MenuItem, FormControl, InputLabel, CircularProgress, Alert, Paper, Divider, List, ListItem, ListItemAvatar, ListItemText, Avatar, Chip, ToggleButtonGroup, ToggleButton, Button, } from '@mui/material'; import { Restaurant, Hotel, BabyChangingStation, TrendingUp, Timeline, Assessment, ChildCare, Add, } from '@mui/icons-material'; import { useRouter } from 'next/navigation'; import { motion } from 'framer-motion'; import { trackingApi, Activity, ActivityType } from '@/lib/api/tracking'; import { childrenApi, Child } from '@/lib/api/children'; import { subDays, startOfDay, endOfDay, parseISO, differenceInMinutes } from 'date-fns'; import { useLocalizedDate } from '@/hooks/useLocalizedDate'; import { useTranslation } from '@/hooks/useTranslation'; import { BarChart, Bar, LineChart, Line, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts'; type DateRange = '7days' | '30days' | '3months'; interface DayData { date: string; feedings: number; sleepHours: number; diapers: number; activities: number; } interface DiaperTypeData { name: string; value: number; color: string; [key: string]: string | number; } interface ActivityTypeData { name: string; count: number; color: string; } const COLORS = { feeding: '#FFB6C1', sleep: '#B6D7FF', diaper: '#FFE4B5', medication: '#D4B5FF', milestone: '#B5FFD4', note: '#FFD3B6', wet: '#87CEEB', dirty: '#D2691E', both: '#FF8C00', dry: '#90EE90', }; const getActivityIcon = (type: ActivityType) => { switch (type) { case 'feeding': return ; case 'sleep': return ; case 'diaper': return ; default: return ; } }; const getActivityColor = (type: ActivityType) => { return COLORS[type as keyof typeof COLORS] || '#CCCCCC'; }; export const InsightsDashboard: React.FC = () => { const router = useRouter(); const { format, formatDistanceToNow } = useLocalizedDate(); const { t } = useTranslation('insights'); const [children, setChildren] = useState([]); const [selectedChild, setSelectedChild] = useState(''); const [dateRange, setDateRange] = useState('7days'); const [activities, setActivities] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Fetch children on mount useEffect(() => { const fetchChildren = async () => { try { const childrenData = await childrenApi.getChildren(); setChildren(childrenData); if (childrenData.length > 0) { setSelectedChild(childrenData[0].id); } } catch (err: any) { setError(err.response?.data?.message || t('errors.loadChildren')); } }; fetchChildren(); }, []); // Fetch activities when child or date range changes useEffect(() => { if (!selectedChild) return; const fetchActivities = async () => { setLoading(true); setError(null); try { const days = dateRange === '7days' ? 7 : dateRange === '30days' ? 30 : 90; const endDate = endOfDay(new Date()); const startDate = startOfDay(subDays(new Date(), days - 1)); const activitiesData = await trackingApi.getActivities( selectedChild, undefined, startDate.toISOString(), endDate.toISOString() ); setActivities(activitiesData); } catch (err: any) { setError(err.response?.data?.message || t('errors.loadActivities')); } finally { setLoading(false); } }; fetchActivities(); }, [selectedChild, dateRange]); // Calculate statistics const calculateStats = () => { const totalFeedings = activities.filter((a) => a.type === 'feeding').length; const totalDiapers = activities.filter((a) => a.type === 'diaper').length; const sleepActivities = activities.filter((a) => a.type === 'sleep'); const totalSleepMinutes = sleepActivities.reduce((acc, activity) => { if (activity.data?.endTime && activity.data?.startTime) { const start = parseISO(activity.data.startTime); const end = parseISO(activity.data.endTime); return acc + differenceInMinutes(end, start); } return acc; }, 0); const days = dateRange === '7days' ? 7 : dateRange === '30days' ? 30 : 90; const avgSleepHours = days > 0 ? (totalSleepMinutes / 60 / days).toFixed(1) : '0.0'; const typeCounts: Record = {}; activities.forEach((a) => { typeCounts[a.type] = (typeCounts[a.type] || 0) + 1; }); const mostCommonType = Object.entries(typeCounts).sort((a, b) => b[1] - a[1])[0]?.[0] || 'none'; return { totalFeedings, avgSleepHours, totalDiapers, mostCommonType, }; }; // Prepare chart data const prepareDailyData = (): DayData[] => { const days = dateRange === '7days' ? 7 : dateRange === '30days' ? 30 : 90; const dailyMap = new Map(); for (let i = days - 1; i >= 0; i--) { const date = format(subDays(new Date(), i), 'yyyy-MM-dd'); dailyMap.set(date, { date: format(subDays(new Date(), i), 'MMM dd'), feedings: 0, sleepHours: 0, diapers: 0, activities: 0, }); } activities.forEach((activity) => { const dateKey = format(parseISO(activity.timestamp), 'yyyy-MM-dd'); const data = dailyMap.get(dateKey); if (data) { data.activities += 1; if (activity.type === 'feeding') data.feedings += 1; if (activity.type === 'diaper') data.diapers += 1; if (activity.type === 'sleep' && activity.data?.endTime && activity.data?.startTime) { const start = parseISO(activity.data.startTime); const end = parseISO(activity.data.endTime); const hours = differenceInMinutes(end, start) / 60; data.sleepHours += hours; } } }); return Array.from(dailyMap.values()).map((d) => ({ ...d, sleepHours: Number(d.sleepHours.toFixed(1)), })); }; const prepareDiaperData = (): DiaperTypeData[] => { const diaperActivities = activities.filter((a) => a.type === 'diaper'); const typeCount: Record = {}; diaperActivities.forEach((activity) => { const type = activity.data?.type || 'unknown'; typeCount[type] = (typeCount[type] || 0) + 1; }); return Object.entries(typeCount).map(([name, value]) => ({ name: t(`diaperTypes.${name}`), value, color: COLORS[name as keyof typeof COLORS] || '#CCCCCC', })); }; const prepareActivityTypeData = (): ActivityTypeData[] => { const typeCount: Record = {}; activities.forEach((activity) => { typeCount[activity.type] = (typeCount[activity.type] || 0) + 1; }); return Object.entries(typeCount).map(([name, count]) => ({ name: t(`activityTypes.${name}`), count, color: COLORS[name as keyof typeof COLORS] || '#CCCCCC', })); }; const stats = calculateStats(); const dailyData = prepareDailyData(); const diaperData = prepareDiaperData(); const activityTypeData = prepareActivityTypeData(); const recentActivities = [...activities] .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()) .slice(0, 20); const noChildren = children.length === 0; const noActivities = activities.length === 0 && !loading; return ( {t('title')} {t('subtitle')} {/* Filters */} {children.length > 1 && ( {t('filters.child')} )} newValue && setDateRange(newValue)} fullWidth size="large" > {t('filters.dateRange.7days')} {t('filters.dateRange.30days')} {t('filters.dateRange.3months')} {error && ( {error} )} {noChildren && !loading && ( {t('emptyStates.noChildren.title')} {t('emptyStates.noChildren.message')} )} {loading && ( )} {noActivities && !noChildren && ( {t('emptyStates.noActivities')} )} {!loading && !noChildren && !noActivities && ( <> {/* Summary Statistics */} {t('stats.feedings.title')} {stats.totalFeedings} {t('stats.feedings.subtitle')} {t('stats.sleep.title')} {stats.avgSleepHours}h {t('stats.sleep.subtitle')} {t('stats.diapers.title')} {stats.totalDiapers} {t('stats.diapers.subtitle')} {t('stats.topActivity.title')} {t(`activityTypes.${stats.mostCommonType}`)} {t('stats.topActivity.subtitle')} {/* Charts */} {t('charts.feedingFrequency')} {t('charts.sleepDuration')} {diaperData.length > 0 && ( {t('charts.diaperChangesByType')} `${name} ${(percent * 100).toFixed(0)}%`} outerRadius={80} fill="#8884d8" dataKey="value" > {diaperData.map((entry, index) => ( ))} )} 0 ? 6 : 12}> {t('charts.activityTimeline')} {activityTypeData.length > 0 && ( {t('charts.activityDistribution')} {activityTypeData.map((activity) => ( ))} )} {/* Recent Activities */} {t('recentActivities.title')} {recentActivities.map((activity, index) => ( {getActivityIcon(activity.type)} {t(`activityTypes.${activity.type}`)} } secondary={ {activity.notes || format(parseISO(activity.timestamp), 'MMM dd, yyyy HH:mm')} } /> ))} )} ); };