'use client'; import { useState, useEffect } from 'react'; import { Box, Typography, Button, Paper, TextField, FormControl, InputLabel, Select, MenuItem, IconButton, Alert, CircularProgress, Card, CardContent, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Chip, Snackbar, } from '@mui/material'; import { ArrowBack, Save, TrendingUp, Delete, Refresh, ChildCare, Add, } from '@mui/icons-material'; import { useRouter } from 'next/navigation'; import { AppShell } from '@/components/layouts/AppShell/AppShell'; import { ProtectedRoute } from '@/components/common/ProtectedRoute'; import { withErrorBoundary } from '@/components/common/ErrorFallbacks'; import { useAuth } from '@/lib/auth/AuthContext'; import { trackingApi, Activity } from '@/lib/api/tracking'; import { childrenApi, Child } from '@/lib/api/children'; import { VoiceInputButton } from '@/components/voice/VoiceInputButton'; import { FormSkeleton, ActivityListSkeleton } from '@/components/common/LoadingSkeletons'; import { motion } from 'framer-motion'; import { useLocalizedDate } from '@/hooks/useLocalizedDate'; import { useTranslation } from '@/hooks/useTranslation'; import { useDispatch, useSelector } from 'react-redux'; import { fetchChildren, selectChild, selectSelectedChild, childrenSelectors } from '@/store/slices/childrenSlice'; import { AppDispatch, RootState } from '@/store/store'; import ChildSelector from '@/components/common/ChildSelector'; import { UnitInput } from '@/components/forms/UnitInput'; interface GrowthData { weight?: number; // in kg height?: number; // in cm headCircumference?: number; // in cm measurementType: 'weight' | 'height' | 'head' | 'all'; } function GrowthTrackPage() { const router = useRouter(); const { user } = useAuth(); const { t } = useTranslation('tracking'); const { formatDistanceToNow } = useLocalizedDate(); const dispatch = useDispatch(); // Redux state const children = useSelector((state: RootState) => childrenSelectors.selectAll(state)); const selectedChild = useSelector(selectSelectedChild); const familyId = useSelector((state: RootState) => state.auth.user?.familyId); // Local state const [selectedChildIds, setSelectedChildIds] = useState([]); // Growth state const [measurementType, setMeasurementType] = useState<'weight' | 'height' | 'head' | 'all'>('weight'); const [weight, setWeight] = useState(0); const [height, setHeight] = useState(0); const [headCircumference, setHeadCircumference] = useState(0); // Common state const [notes, setNotes] = useState(''); const [recentGrowth, setRecentGrowth] = useState([]); const [loading, setLoading] = useState(false); const [childrenLoading, setChildrenLoading] = useState(true); const [growthLoading, setGrowthLoading] = useState(false); const [error, setError] = useState(null); const [successMessage, setSuccessMessage] = useState(null); // Delete confirmation dialog const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [activityToDelete, setActivityToDelete] = useState(null); const familyId = user?.families?.[0]?.familyId; // Load children useEffect(() => { if (familyId) { loadChildren(); } }, [familyId]); // Load recent growth when child is selected useEffect(() => { if (selectedChild) { loadRecentGrowth(); } }, [selectedChild]); const loadChildren = async () => { if (!familyId) return; try { setChildrenLoading(true); const childrenData = await childrenApi.getChildren(familyId); setChildren(childrenData); if (childrenData.length > 0) { setSelectedChild(childrenData[0].id); } } catch (err: any) { console.error('Failed to load children:', err); setError(err.response?.data?.message || t('common.error.loadChildrenFailed')); } finally { setChildrenLoading(false); } }; const loadRecentGrowth = async () => { if (!selectedChild) return; try { setGrowthLoading(true); const activities = await trackingApi.getActivities(selectedChild, 'growth'); const sorted = activities.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime() ).slice(0, 10); setRecentGrowth(sorted); } catch (err: any) { console.error('Failed to load recent growth:', err); } finally { setGrowthLoading(false); } }; const handleSubmit = async () => { if (!selectedChild) { setError(t('common.selectChild')); return; } // Validation if (measurementType === 'weight' && weight === 0) { setError('Please enter weight'); return; } if (measurementType === 'height' && height === 0) { setError('Please enter height'); return; } if (measurementType === 'head' && headCircumference === 0) { setError('Please enter head circumference'); return; } if (measurementType === 'all' && (weight === 0 || height === 0 || headCircumference === 0)) { setError('Please enter all measurements'); return; } try { setLoading(true); setError(null); const data: GrowthData = { measurementType, ...(measurementType === 'weight' || measurementType === 'all' ? { weight } : {}), ...(measurementType === 'height' || measurementType === 'all' ? { height } : {}), ...(measurementType === 'head' || measurementType === 'all' ? { headCircumference } : {}), }; await trackingApi.createActivity(selectedChild, { type: 'growth', timestamp: new Date().toISOString(), data, notes: notes || undefined, }); setSuccessMessage('Growth measurement logged successfully!'); // Reset form resetForm(); // Reload recent growth await loadRecentGrowth(); } catch (err: any) { console.error('Failed to save growth:', err); setError(err.response?.data?.message || 'Failed to save growth measurement'); } finally { setLoading(false); } }; const resetForm = () => { setWeight(0); setHeight(0); setHeadCircumference(0); setMeasurementType('weight'); setNotes(''); }; const handleDeleteClick = (activityId: string) => { setActivityToDelete(activityId); setDeleteDialogOpen(true); }; const handleDeleteConfirm = async () => { if (!activityToDelete) return; try { setLoading(true); await trackingApi.deleteActivity(activityToDelete); setSuccessMessage('Growth measurement deleted successfully'); setDeleteDialogOpen(false); setActivityToDelete(null); await loadRecentGrowth(); } catch (err: any) { console.error('Failed to delete growth:', err); setError(err.response?.data?.message || 'Failed to delete growth measurement'); } finally { setLoading(false); } }; const getGrowthDetails = (activity: Activity) => { const data = activity.data as GrowthData; const details: string[] = []; if (data.weight) { const measurementSystem = (user?.preferences?.measurementUnit as 'metric' | 'imperial') || 'metric'; if (measurementSystem === 'imperial') { const lbs = (data.weight * 2.20462).toFixed(1); details.push(`Weight: ${lbs} lbs`); } else { details.push(`Weight: ${data.weight} kg`); } } if (data.height) { const measurementSystem = (user?.preferences?.measurementUnit as 'metric' | 'imperial') || 'metric'; if (measurementSystem === 'imperial') { const inches = (data.height * 0.393701).toFixed(1); details.push(`Height: ${inches} in`); } else { details.push(`Height: ${data.height} cm`); } } if (data.headCircumference) { const measurementSystem = (user?.preferences?.measurementUnit as 'metric' | 'imperial') || 'metric'; if (measurementSystem === 'imperial') { const inches = (data.headCircumference * 0.393701).toFixed(1); details.push(`Head: ${inches} in`); } else { details.push(`Head: ${data.headCircumference} cm`); } } return details.join(' | '); }; if (childrenLoading) { return ( {t('activities.growth')} ); } if (!familyId || children.length === 0) { return ( {t('common.noChildrenAdded')} {t('common.noChildrenMessage')} ); } return ( router.back()} sx={{ mr: 2 }}> {t('activities.growth')} { console.log('[Growth] Voice transcript:', transcript); }} onClassifiedIntent={(result) => { console.log('[Growth] Intent:', result); }} size="medium" /> {error && ( setError(null)}> {error} )} {/* Child Selector */} {children.length > 1 && ( {t('common.selectChild')} )} {/* Main Form */} Growth Measurement Measurement Type {(measurementType === 'weight' || measurementType === 'all') && ( setWeight(metricValue)} required sx={{ mb: 3 }} /> )} {(measurementType === 'height' || measurementType === 'all') && ( setHeight(metricValue)} required sx={{ mb: 3 }} /> )} {(measurementType === 'head' || measurementType === 'all') && ( setHeadCircumference(metricValue)} required sx={{ mb: 3 }} /> )} setNotes(e.target.value)} sx={{ mb: 3 }} placeholder="Add any notes about this measurement..." /> {/* Recent Growth */} Recent Growth Measurements {growthLoading ? ( ) : recentGrowth.length === 0 ? ( {t('noEntries')} ) : ( {recentGrowth.map((activity, index) => ( Growth Measurement {getGrowthDetails(activity)} {activity.notes && ( {activity.notes} )} handleDeleteClick(activity.id)} disabled={loading} > ))} )} {/* Delete Confirmation Dialog */} setDeleteDialogOpen(false)} > {t('deleteEntry')} {t('confirmDelete')} {/* Success Snackbar */} setSuccessMessage(null)} message={successMessage} /> ); } export default withErrorBoundary(GrowthTrackPage, 'form');