From 654a514f2b4f2d28f523ed70eada8445de447c65 Mon Sep 17 00:00:00 2001 From: Andrei Date: Sat, 4 Oct 2025 22:23:29 +0000 Subject: [PATCH] feat: Integrate ChildSelector in diaper tracking form - Replace local child state with Redux state management - Use ChildSelector component instead of custom select - Sync selectedChildIds with Redux store - Update API calls to use selectedChild.id - Remove loadChildren function --- maternal-web/app/track/diaper/page.tsx | 96 +++++++++++++------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/maternal-web/app/track/diaper/page.tsx b/maternal-web/app/track/diaper/page.tsx index 5ea3caf..651a3bb 100644 --- a/maternal-web/app/track/diaper/page.tsx +++ b/maternal-web/app/track/diaper/page.tsx @@ -48,6 +48,10 @@ import { childrenApi, Child } from '@/lib/api/children'; 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'; interface DiaperData { diaperType: 'wet' | 'dirty' | 'both' | 'dry'; @@ -62,8 +66,15 @@ export default function DiaperTrackPage() { const { user } = useAuth(); const { t } = useTranslation('tracking'); const { formatDistanceToNow, format } = useLocalizedDate(); - const [children, setChildren] = useState([]); - const [selectedChild, setSelectedChild] = useState(''); + 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([]); // Diaper state const [timestamp, setTimestamp] = useState( @@ -78,7 +89,6 @@ export default function DiaperTrackPage() { const [notes, setNotes] = useState(''); const [recentDiapers, setRecentDiapers] = useState([]); const [loading, setLoading] = useState(false); - const [childrenLoading, setChildrenLoading] = useState(true); const [diapersLoading, setDiapersLoading] = useState(false); const [error, setError] = useState(null); const [successMessage, setSuccessMessage] = useState(null); @@ -87,8 +97,6 @@ export default function DiaperTrackPage() { const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [activityToDelete, setActivityToDelete] = useState(null); - const familyId = user?.families?.[0]?.familyId; - const availableConditions = [ 'normal', 'soft', @@ -98,19 +106,26 @@ export default function DiaperTrackPage() { 'blood', ]; - // Load children + // Load children from Redux useEffect(() => { - if (familyId) { - loadChildren(); + if (familyId && children.length === 0) { + dispatch(fetchChildren(familyId)); } - }, [familyId]); + }, [familyId, dispatch, children.length]); + + // Sync selectedChildIds with Redux selectedChild + useEffect(() => { + if (selectedChild?.id) { + setSelectedChildIds([selectedChild.id]); + } + }, [selectedChild]); // Load recent diapers when child is selected useEffect(() => { - if (selectedChild) { + if (selectedChild?.id) { loadRecentDiapers(); } - }, [selectedChild]); + }, [selectedChild?.id]); // Pre-fill form from URL parameters (voice command) useEffect(() => { @@ -164,30 +179,12 @@ export default function DiaperTrackPage() { } }, [searchParams]); - 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 || 'Failed to load children'); - } finally { - setChildrenLoading(false); - } - }; - const loadRecentDiapers = async () => { - if (!selectedChild) return; + if (!selectedChild?.id) return; try { setDiapersLoading(true); - const activities = await trackingApi.getActivities(selectedChild, 'diaper'); + const activities = await trackingApi.getActivities(selectedChild.id, 'diaper'); // Sort by timestamp descending and take last 10 const sorted = activities.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime() @@ -217,7 +214,7 @@ export default function DiaperTrackPage() { }; const handleSubmit = async () => { - if (!selectedChild) { + if (!selectedChild?.id) { setError('Please select a child'); return; } @@ -247,7 +244,7 @@ export default function DiaperTrackPage() { data.rashSeverity = rashSeverity; } - await trackingApi.createActivity(selectedChild, { + await trackingApi.createActivity(selectedChild.id, { type: 'diaper', timestamp, data, @@ -361,7 +358,9 @@ export default function DiaperTrackPage() { } }; - if (childrenLoading) { + const childrenLoading = useSelector((state: RootState) => state.children.loading); + + if (childrenLoading && children.length === 0) { return ( @@ -434,22 +433,21 @@ export default function DiaperTrackPage() { transition={{ duration: 0.3 }} > {/* Child Selector */} - {children.length > 1 && ( + {children.length > 0 && ( - - {t('common.selectChild')} - - + { + setSelectedChildIds(childIds); + if (childIds.length > 0) { + dispatch(selectChild(childIds[0])); + } + }} + mode="single" + label={t('common.selectChild')} + required + /> )}