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
This commit is contained in:
@@ -48,6 +48,10 @@ import { childrenApi, Child } from '@/lib/api/children';
|
|||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { useLocalizedDate } from '@/hooks/useLocalizedDate';
|
import { useLocalizedDate } from '@/hooks/useLocalizedDate';
|
||||||
import { useTranslation } from '@/hooks/useTranslation';
|
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 {
|
interface DiaperData {
|
||||||
diaperType: 'wet' | 'dirty' | 'both' | 'dry';
|
diaperType: 'wet' | 'dirty' | 'both' | 'dry';
|
||||||
@@ -62,8 +66,15 @@ export default function DiaperTrackPage() {
|
|||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const { t } = useTranslation('tracking');
|
const { t } = useTranslation('tracking');
|
||||||
const { formatDistanceToNow, format } = useLocalizedDate();
|
const { formatDistanceToNow, format } = useLocalizedDate();
|
||||||
const [children, setChildren] = useState<Child[]>([]);
|
const dispatch = useDispatch<AppDispatch>();
|
||||||
const [selectedChild, setSelectedChild] = useState<string>('');
|
|
||||||
|
// 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<string[]>([]);
|
||||||
|
|
||||||
// Diaper state
|
// Diaper state
|
||||||
const [timestamp, setTimestamp] = useState<string>(
|
const [timestamp, setTimestamp] = useState<string>(
|
||||||
@@ -78,7 +89,6 @@ export default function DiaperTrackPage() {
|
|||||||
const [notes, setNotes] = useState<string>('');
|
const [notes, setNotes] = useState<string>('');
|
||||||
const [recentDiapers, setRecentDiapers] = useState<Activity[]>([]);
|
const [recentDiapers, setRecentDiapers] = useState<Activity[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [childrenLoading, setChildrenLoading] = useState(true);
|
|
||||||
const [diapersLoading, setDiapersLoading] = useState(false);
|
const [diapersLoading, setDiapersLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
||||||
@@ -87,8 +97,6 @@ export default function DiaperTrackPage() {
|
|||||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||||
const [activityToDelete, setActivityToDelete] = useState<string | null>(null);
|
const [activityToDelete, setActivityToDelete] = useState<string | null>(null);
|
||||||
|
|
||||||
const familyId = user?.families?.[0]?.familyId;
|
|
||||||
|
|
||||||
const availableConditions = [
|
const availableConditions = [
|
||||||
'normal',
|
'normal',
|
||||||
'soft',
|
'soft',
|
||||||
@@ -98,19 +106,26 @@ export default function DiaperTrackPage() {
|
|||||||
'blood',
|
'blood',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Load children
|
// Load children from Redux
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (familyId) {
|
if (familyId && children.length === 0) {
|
||||||
loadChildren();
|
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
|
// Load recent diapers when child is selected
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedChild) {
|
if (selectedChild?.id) {
|
||||||
loadRecentDiapers();
|
loadRecentDiapers();
|
||||||
}
|
}
|
||||||
}, [selectedChild]);
|
}, [selectedChild?.id]);
|
||||||
|
|
||||||
// Pre-fill form from URL parameters (voice command)
|
// Pre-fill form from URL parameters (voice command)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -164,30 +179,12 @@ export default function DiaperTrackPage() {
|
|||||||
}
|
}
|
||||||
}, [searchParams]);
|
}, [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 () => {
|
const loadRecentDiapers = async () => {
|
||||||
if (!selectedChild) return;
|
if (!selectedChild?.id) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setDiapersLoading(true);
|
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
|
// Sort by timestamp descending and take last 10
|
||||||
const sorted = activities.sort((a, b) =>
|
const sorted = activities.sort((a, b) =>
|
||||||
new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
|
new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
|
||||||
@@ -217,7 +214,7 @@ export default function DiaperTrackPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
if (!selectedChild) {
|
if (!selectedChild?.id) {
|
||||||
setError('Please select a child');
|
setError('Please select a child');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -247,7 +244,7 @@ export default function DiaperTrackPage() {
|
|||||||
data.rashSeverity = rashSeverity;
|
data.rashSeverity = rashSeverity;
|
||||||
}
|
}
|
||||||
|
|
||||||
await trackingApi.createActivity(selectedChild, {
|
await trackingApi.createActivity(selectedChild.id, {
|
||||||
type: 'diaper',
|
type: 'diaper',
|
||||||
timestamp,
|
timestamp,
|
||||||
data,
|
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 (
|
return (
|
||||||
<ProtectedRoute>
|
<ProtectedRoute>
|
||||||
<AppShell>
|
<AppShell>
|
||||||
@@ -434,22 +433,21 @@ export default function DiaperTrackPage() {
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
>
|
>
|
||||||
{/* Child Selector */}
|
{/* Child Selector */}
|
||||||
{children.length > 1 && (
|
{children.length > 0 && (
|
||||||
<Paper sx={{ p: 2, mb: 3 }}>
|
<Paper sx={{ p: 2, mb: 3 }}>
|
||||||
<FormControl fullWidth>
|
<ChildSelector
|
||||||
<InputLabel>{t('common.selectChild')}</InputLabel>
|
children={children}
|
||||||
<Select
|
selectedChildIds={selectedChildIds}
|
||||||
value={selectedChild}
|
onChange={(childIds) => {
|
||||||
onChange={(e) => setSelectedChild(e.target.value)}
|
setSelectedChildIds(childIds);
|
||||||
label={t('common.selectChild')}
|
if (childIds.length > 0) {
|
||||||
>
|
dispatch(selectChild(childIds[0]));
|
||||||
{children.map((child) => (
|
}
|
||||||
<MenuItem key={child.id} value={child.id}>
|
}}
|
||||||
{child.name}
|
mode="single"
|
||||||
</MenuItem>
|
label={t('common.selectChild')}
|
||||||
))}
|
required
|
||||||
</Select>
|
/>
|
||||||
</FormControl>
|
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user