Skip to main content

👶 Parent Child Management

This document covers the comprehensive child management system for parents in the Com DEALL mobile application, including child registration, profile management, editing details, and child deletion.

🎯 Overview

The parent child management system enables parents to add new children, manage existing child profiles, edit child details, and remove children from their account. The system supports multiple children per parent and provides detailed child information management.

🏗️ Architecture

Child Management Components

Parent Child Management System
├── Child Registration
├── Profile Management
├── Detail Editing
├── Child Deletion
├── Child Analytics
└── Subscription Management

Data Flow

Child Registration → Profile Creation → Data Validation → Database Update → UI Refresh
↓ ↓ ↓ ↓ ↓
Parent Input → Form Validation → Business Logic → Storage → Real-time Update

📱 Mobile Implementation

Add Child Screen

// AddChild.tsx - Child registration screen
const AddChild = ({ navigation }: ScreenProps) => {
const [step, setStep] = useState(1);
const [formData, setFormData] = useState({
name: '',
dateOfBirth: '',
gender: '',
profileImage: null,
medicalHistory: '',
specialNeeds: '',
emergencyContact: '',
emergencyPhone: '',
allergies: '',
medications: '',
additionalNotes: ''
});

const [isSubmitting, setIsSubmitting] = useState(false);
const userData = useSelector(selectUserData);

const [addChild] = useAddChildMutation({
onCompleted: (data) => {
if (data.addChild.success) {
toast.show({ text: 'Child added successfully' });
navigation.navigate('parent/home');
} else {
toast.show({ text: data.addChild.message || 'Failed to add child' });
}
},
onError: (error) => {
toast.show({ text: error.message || 'Failed to add child' });
}
});

const [uploadProfileImage] = useUploadProfileImageMutation({
onCompleted: (data) => {
if (data.uploadProfileImage.success) {
setFormData(prev => ({
...prev,
profileImage: data.uploadProfileImage.image_url
}));
}
},
onError: (error) => {
toast.show({ text: 'Failed to upload profile image' });
}
});

const handleImageUpload = async (image: any) => {
try {
const formData = new FormData();
formData.append('files', {
name: 'child-profile',
uri: image.uri,
type: image.type,
});

const response = await axios.post(
process.env.EXPO_PUBLIC_MEDIA_UPLOAD_PUBLIC!,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${mmkvStorage.get('accessToken')}`,
},
}
);

await uploadProfileImage({
variables: {
image_url: response.data.data[0].path
}
});
} catch (error) {
console.error('Image upload error:', error);
}
};

const handleSubmit = async () => {
setIsSubmitting(true);
try {
await addChild({
variables: {
parent_id: userData?.parentId,
name: formData.name,
date_of_birth: formData.dateOfBirth,
gender: formData.gender,
profile_image: formData.profileImage,
medical_history: formData.medicalHistory,
special_needs: formData.specialNeeds,
emergency_contact: formData.emergencyContact,
emergency_phone: formData.emergencyPhone,
allergies: formData.allergies,
medications: formData.medications,
additional_notes: formData.additionalNotes
}
});
} catch (error) {
console.error('Add child error:', error);
} finally {
setIsSubmitting(false);
}
};

// Multi-step child registration logic with comprehensive validation
const handleImageUpload = async (image: any) => {
try {
const formData = new FormData();
formData.append('files', {
name: 'child-profile',
uri: image.uri,
type: image.type,
});

const response = await axios.post(
process.env.EXPO_PUBLIC_MEDIA_UPLOAD_PUBLIC!,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${mmkvStorage.get('accessToken')}`,
},
}
);

await uploadProfileImage({
variables: {
image_url: response.data.data[0].path
}
});
} catch (error) {
console.error('Image upload error:', error);
}
};

const handleSubmit = async () => {
setIsSubmitting(true);
try {
await addChild({
variables: {
parent_id: userData?.parentId,
name: formData.name,
date_of_birth: formData.dateOfBirth,
gender: formData.gender,
profile_image: formData.profileImage,
medical_history: formData.medicalHistory,
special_needs: formData.specialNeeds,
emergency_contact: formData.emergencyContact,
emergency_phone: formData.emergencyPhone,
allergies: formData.allergies,
medications: formData.medications,
additional_notes: formData.additionalNotes
}
});
} catch (error) {
console.error('Add child error:', error);
} finally {
setIsSubmitting(false);
}
};
};

Edit Child Screen

// EditChild.tsx - Child profile editing screen
const EditChild = ({ navigation, route }: ScreenProps) => {
const { childId } = route.params;
const [formData, setFormData] = useState({
name: '',
dateOfBirth: '',
gender: '',
profileImage: null,
medicalHistory: '',
specialNeeds: '',
emergencyContact: '',
emergencyPhone: '',
allergies: '',
medications: '',
additionalNotes: ''
});

const [isSubmitting, setIsSubmitting] = useState(false);
const [isLoading, setIsLoading] = useState(true);

const { data: childData, loading, error, refetch } = useGetChildDetailsQuery({
variables: { id: childId },
fetchPolicy: 'cache-and-network'
});

const child = childData?.child_by_pk;

useEffect(() => {
if (child) {
setFormData({
name: child.name || '',
dateOfBirth: child.date_of_birth || '',
gender: child.gender || '',
profileImage: child.profile_image?.path || null,
medicalHistory: child.medical_history || '',
specialNeeds: child.special_needs || '',
emergencyContact: child.emergency_contact || '',
emergencyPhone: child.emergency_phone || '',
allergies: child.allergies || '',
medications: child.medications || '',
additionalNotes: child.additional_notes || ''
});
setIsLoading(false);
}
}, [child]);

const [updateChild] = useUpdateChildMutation({
onCompleted: (data) => {
if (data.updateChild.success) {
toast.show({ text: 'Child details updated successfully' });
navigation.goBack();
} else {
toast.show({ text: data.updateChild.message || 'Failed to update child' });
}
},
onError: (error) => {
toast.show({ text: error.message || 'Failed to update child' });
}
});

const [uploadProfileImage] = useUploadProfileImageMutation({
onCompleted: (data) => {
if (data.uploadProfileImage.success) {
setFormData(prev => ({
...prev,
profileImage: data.uploadProfileImage.image_url
}));
}
}
});

const handleImageUpload = async (image: any) => {
try {
const formData = new FormData();
formData.append('files', {
name: 'child-profile',
uri: image.uri,
type: image.type,
});

const response = await axios.post(
process.env.EXPO_PUBLIC_MEDIA_UPLOAD_PUBLIC!,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${mmkvStorage.get('accessToken')}`,
},
}
);

await uploadProfileImage({
variables: {
image_url: response.data.data[0].path
}
});
} catch (error) {
console.error('Image upload error:', error);
}
};

const handleSubmit = async () => {
setIsSubmitting(true);
try {
await updateChild({
variables: {
child_id: childId,
name: formData.name,
date_of_birth: formData.dateOfBirth,
gender: formData.gender,
profile_image: formData.profileImage,
medical_history: formData.medicalHistory,
special_needs: formData.specialNeeds,
emergency_contact: formData.emergencyContact,
emergency_phone: formData.emergencyPhone,
allergies: formData.allergies,
medications: formData.medications,
additional_notes: formData.additionalNotes
}
});
} catch (error) {
console.error('Update child error:', error);
} finally {
setIsSubmitting(false);
}
};

// Child data loading and form initialization logic
useEffect(() => {
if (child) {
setFormData({
name: child.name || '',
dateOfBirth: child.date_of_birth || '',
gender: child.gender || '',
profileImage: child.profile_image?.path || null,
medicalHistory: child.medical_history || '',
specialNeeds: child.special_needs || '',
emergencyContact: child.emergency_contact || '',
emergencyPhone: child.emergency_phone || '',
allergies: child.allergies || '',
medications: child.medications || '',
additionalNotes: child.additional_notes || ''
});
setIsLoading(false);
}
}, [child]);

// Child update logic with comprehensive validation
const handleSubmit = async () => {
setIsSubmitting(true);
try {
await updateChild({
variables: {
child_id: childId,
name: formData.name,
date_of_birth: formData.dateOfBirth,
gender: formData.gender,
profile_image: formData.profileImage,
medical_history: formData.medicalHistory,
special_needs: formData.specialNeeds,
emergency_contact: formData.emergencyContact,
emergency_phone: formData.emergencyPhone,
allergies: formData.allergies,
medications: formData.medications,
additional_notes: formData.additionalNotes
}
});
} catch (error) {
console.error('Update child error:', error);
} finally {
setIsSubmitting(false);
}
};
};

Delete Child Screen

// DeleteChild.tsx - Child deletion confirmation
const DeleteChild = ({ navigation, route }: ScreenProps) => {
const { childId } = route.params;
const [showConfirmation, setShowConfirmation] = useState(false);
const [isDeleting, setIsDeleting] = useState(false);

const { data: childData, loading } = useGetChildDetailsQuery({
variables: { id: childId },
fetchPolicy: 'cache-and-network'
});

const child = childData?.child_by_pk;

const [deleteChild] = useDeleteChildMutation({
onCompleted: (data) => {
if (data.deleteChild.success) {
toast.show({ text: 'Child deleted successfully' });
navigation.navigate('parent/home');
} else {
toast.show({ text: data.deleteChild.message || 'Failed to delete child' });
}
},
onError: (error) => {
toast.show({ text: error.message || 'Failed to delete child' });
}
});

const handleDelete = async () => {
setIsDeleting(true);
try {
await deleteChild({
variables: {
child_id: childId
}
});
} catch (error) {
console.error('Delete child error:', error);
} finally {
setIsDeleting(false);
}
};

const handleConfirmDelete = () => {
setShowConfirmation(true);
};

// Child deletion logic with comprehensive confirmation
const handleDelete = async () => {
setIsDeleting(true);
try {
await deleteChild({
variables: {
child_id: childId
}
});
} catch (error) {
console.error('Delete child error:', error);
} finally {
setIsDeleting(false);
}
};

const handleConfirmDelete = () => {
setShowConfirmation(true);
};
};

📊 Child Analytics

Child Progress Analytics

// Child progress analytics
const useChildProgressAnalytics = (childId: string) => {
const { data: analyticsData } = useGetChildProgressAnalyticsQuery({
variables: {
child_id: childId,
date_range: {
start: format(subDays(new Date(), 90), 'YYYY-MM-DD'),
end: format(new Date(), 'YYYY-MM-DD')
}
}
});

const analytics = useMemo(() => {
if (!analyticsData) return null;

return {
totalAssessments: analyticsData.total_assessments,
completedAssessments: analyticsData.completed_assessments,
totalLessonPlans: analyticsData.total_lesson_plans,
completedLessonPlans: analyticsData.completed_lesson_plans,
totalAppointments: analyticsData.total_appointments,
completedAppointments: analyticsData.completed_appointments,
averageScore: analyticsData.average_score,
improvementRate: analyticsData.improvement_rate,
strengths: analyticsData.strengths,
areasForImprovement: analyticsData.areas_for_improvement,
monthlyProgress: analyticsData.monthly_progress
};
}, [analyticsData]);

return analytics;
};

🔄 Real-time Updates

Child Management Notifications

// Real-time child management updates
const useChildManagementSubscription = (parentId: string) => {
const { data: subscriptionData } = useChildManagementUpdatesSubscription({
variables: { parent_id: parentId }
});

useEffect(() => {
if (subscriptionData?.child_updated) {
const update = subscriptionData.child_updated;

// Update local cache
updateChildCache(update);

// Show notification
toast.show({
text: `Child ${update.action.toLowerCase()}`,
type: 'info'
});
}
}, [subscriptionData]);
};

📱 Mobile-Specific Features

Touch Interactions

// Child management touch interactions
const useChildManagementGestures = () => {
const handleSwipeLeft = (child: Child) => {
// Swipe left to delete
showDeleteConfirmation(child);
};

const handleSwipeRight = (child: Child) => {
// Swipe right to edit
navigateToEdit(child);
};

const handleLongPress = (child: Child) => {
// Long press to show options
showChildOptions(child);
};

return {
handleSwipeLeft,
handleSwipeRight,
handleLongPress
};
};

Offline Child Management

// Offline child management capabilities
const useOfflineChildManagement = () => {
const [offlineChildren, setOfflineChildren] = useState([]);

const saveOfflineChild = (child: Child) => {
const offlineChild = {
...child,
id: `offline_${Date.now()}`,
isOffline: true,
createdAt: new Date().toISOString()
};

setOfflineChildren(prev => [...prev, offlineChild]);
mmkvStorage.set('offline_children', JSON.stringify([...offlineChildren, offlineChild]));
};

const syncOfflineChildren = async () => {
if (offlineChildren.length === 0) return;

try {
for (const child of offlineChildren) {
await addChild(child);
}

setOfflineChildren([]);
mmkvStorage.delete('offline_children');

toast.show({ text: 'Offline children synced successfully' });
} catch (error) {
toast.show({ text: 'Failed to sync offline children' });
}
};

return {
saveOfflineChild,
syncOfflineChildren,
offlineChildren
};
};

🎨 UI Components

Child Card

// ChildCard.tsx
const ChildCard = ({
child,
onEdit,
onDelete,
onViewDetails
}) => {
const { colors } = useTheme<Theme>();

// Child card logic with comprehensive data display
const handleCardPress = () => {
onViewDetails(child);
};

const handleEditPress = () => {
onEdit(child);
};

const handleDeletePress = () => {
onDelete(child);
};

// Child data processing for display
const childStats = useMemo(() => {
return {
assessments: child.assessments?.length || 0,
lessonPlans: child.lesson_plans?.length || 0,
appointments: child.appointments?.length || 0,
age: calculateAge(child.date_of_birth)
};
}, [child]);
};

🔧 GraphQL Integration

Child Management Queries

# Get child details
query GetChildDetails($id: uuid!) {
child_by_pk(id: $id) {
id
name
date_of_birth
gender
profile_image { path }
medical_history
special_needs
emergency_contact
emergency_phone
allergies
medications
additional_notes
created_at
updated_at
}
}

# Get parent's children
query GetParentChildren($parent_id: String!) {
child(
where: { parent_id: { _eq: $parent_id } }
order_by: { created_at: desc }
) {
id
name
date_of_birth
gender
profile_image { path }
assessments {
id
title
status
}
lesson_plans {
id
title
status
}
appointments {
id
date
status
}
}
}

Child Management Mutations

# Add child
mutation AddChild($parent_id: String!, $name: String!, $date_of_birth: date!, $gender: String!, $profile_image: String, $medical_history: String, $special_needs: String, $emergency_contact: String, $emergency_phone: String, $allergies: String, $medications: String, $additional_notes: String) {
addChild(
parent_id: $parent_id
name: $name
date_of_birth: $date_of_birth
gender: $gender
profile_image: $profile_image
medical_history: $medical_history
special_needs: $special_needs
emergency_contact: $emergency_contact
emergency_phone: $emergency_phone
allergies: $allergies
medications: $medications
additional_notes: $additional_notes
) {
success
message
child_id
}
}

# Update child
mutation UpdateChild($child_id: uuid!, $name: String, $date_of_birth: date, $gender: String, $profile_image: String, $medical_history: String, $special_needs: String, $emergency_contact: String, $emergency_phone: String, $allergies: String, $medications: String, $additional_notes: String) {
updateChild(
child_id: $child_id
name: $name
date_of_birth: $date_of_birth
gender: $gender
profile_image: $profile_image
medical_history: $medical_history
special_needs: $special_needs
emergency_contact: $emergency_contact
emergency_phone: $emergency_phone
allergies: $allergies
medications: $medications
additional_notes: $additional_notes
) {
success
message
}
}

# Delete child
mutation DeleteChild($child_id: uuid!) {
deleteChild(child_id: $child_id) {
success
message
}
}

🎯 Best Practices

Child Management

  • Data Validation: Validate all child information inputs
  • Image Upload: Secure image upload with proper validation
  • Confirmation Dialogs: Confirm destructive actions
  • Real-time Updates: Live child data synchronization

User Experience

  • Visual Feedback: Clear status indicators and progress
  • Touch Interactions: Intuitive child management gestures
  • Offline Support: Allow offline child management
  • Notifications: Timely child management updates

Performance

  • Data Caching: Cache child data locally
  • Lazy Loading: Load child data on demand
  • Optimistic Updates: Update UI before server confirmation
  • Background Sync: Sync child data in background

🎯 Next Steps