This commit adds a complete onboarding improvements system including progress
tracking, streamlined UI, and role-based family invitation system.
## Backend Changes
### Database Migrations
- Add onboarding tracking fields to users table (onboarding_completed, onboarding_step, onboarding_data)
- Add role-based invite codes to families table (parent/caregiver/viewer codes with expiration)
- Add indexes for fast invite code lookups
### User Preferences Module
- Add UserPreferencesController with onboarding endpoints
- Add UserPreferencesService with progress tracking methods
- Add UpdateOnboardingProgressDto for validation
- Endpoints: GET/PUT /api/v1/preferences/onboarding, POST /api/v1/preferences/onboarding/complete
### Families Module - Role-Based Invites
- Add generateRoleInviteCode() - Generate role-specific codes with expiration
- Add getRoleInviteCodes() - Retrieve all active codes for a family
- Add joinFamilyWithRoleCode() - Join family with automatic role assignment
- Add revokeRoleInviteCode() - Revoke specific role invite codes
- Add sendEmailInvite() - Generate code and send email invitation
- Endpoints: POST/GET/DELETE /api/v1/families/:id/invite-codes, POST /api/v1/families/join-with-role, POST /api/v1/families/:id/email-invite
### Email Service
- Add sendFamilyInviteEmail() - Send role-based invitation emails
- Beautiful HTML templates with role badges (👨👩👧 parent, 🤝 caregiver, 👁️ viewer)
- Role-specific permission descriptions
- Graceful fallback if email sending fails
### Auth Service
- Fix duplicate family creation bug in joinFamily()
- Ensure users only join family once during onboarding
## Frontend Changes
### Onboarding Page
- Reduce steps from 5 to 4 (combined language + measurements)
- Replace card-based selection with dropdown selectors
- Add automatic progress saving after each step
- Add progress restoration on page mount
- Extract FamilySetupStep into reusable component
### Family Page
- Add RoleInvitesSection component with accordion UI
- Generate/view/copy/regenerate/revoke controls for each role
- Send email invites directly from UI
- Display expiration dates (e.g., "Expires in 5 days")
- Info tooltips explaining role permissions
- Only visible to users with parent role
### API Client
- Add role-based invite methods to families API
- Add onboarding progress methods to users API
- TypeScript interfaces for all new data structures
## Features
✅ Streamlined 4-step onboarding with dropdown selectors
✅ Automatic progress save/restore across sessions
✅ Role-based family invites (parent/caregiver/viewer)
✅ Beautiful email invitations with role descriptions
✅ Automatic role assignment when joining with invite codes
✅ Granular permission control per role
✅ Email fallback if sending fails
✅ All changes tested and production-ready
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements Phase 1 of notification bell feature with:
- NotificationBell component with badge counter (99+ max)
- useNotifications hook with 30s polling and caching
- Notifications API client for backend integration
- Integration into AppShell header next to user avatar
- Responsive dropdown (400px desktop, full-width mobile)
- Empty state, loading, and error handling
- Optimistic UI updates for mark as read
- Animated badge with pulse effect
- Icon mapping for notification types
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement database-backed notification settings that persist across restarts:
Backend changes:
- Updated DashboardService to read/write notification settings from database
- Added 6 notification settings keys to dbSettingsMap:
* enable_email_notifications (boolean)
* enable_push_notifications (boolean)
* admin_notifications (boolean)
* error_alerts (boolean)
* new_user_alerts (boolean)
* system_health_alerts (boolean)
- Settings are now retrieved from database with fallback defaults
Database:
- Seeded 6 default notification settings in settings table
- All notification toggles default to 'true'
- Settings persist across server restarts
Frontend:
- Admin settings page at /settings already configured
- Notifications tab contains all 6 toggle switches
- Settings are loaded from GET /api/v1/admin/dashboard/settings
- Settings are saved via POST /api/v1/admin/dashboard/settings
API Endpoints (already existed, now enhanced):
- GET /api/v1/admin/dashboard/settings - Returns all settings including notifications
- POST /api/v1/admin/dashboard/settings - Persists notification settings to database
Files modified:
- maternal-app-backend/src/modules/admin/dashboard/dashboard.service.ts
Benefits:
✅ Global notification settings are now persistent
✅ Admin can control email/push notifications globally
✅ Admin can configure alert preferences
✅ Settings survive server restarts and deployments
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Created EnhancedInsightsDashboard with multiple chart types:
- Area charts with gradients for activity trends
- Radar chart for weekly activity patterns
- 24-hour heatmap visualization
- Bubble/scatter chart for correlations
- Time of day distribution bar chart
- Added toggle between basic and enhanced chart views
- Implemented chart export functionality (PNG/PDF)
- Fixed API endpoint URLs (circadian-rhythm, query params)
- Fixed component library conflicts (shadcn/ui → MUI)
- Added comprehensive null safety for timestamp handling
- Added alert type translations in all 5 languages
- Installed html2canvas and jspdf for export features
- Applied consistent minimum width styling to all charts
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add comprehensive API client methods for all advanced analytics endpoints
- Create CircadianRhythmCard component for sleep pattern visualization
- Create AnomalyAlertsPanel for anomaly detection and alerts
- Create GrowthPercentileChart with WHO/CDC percentiles
- Create CorrelationInsights for activity correlations
- Create TrendAnalysisChart with predictions
- Add advanced analytics page with all new components
- Add UI component library (shadcn/ui) setup
- Add navigation link to advanced analytics from insights page
All advanced analytics features are now accessible from the frontend UI.
- Replace basic Select dropdown with ChildSelector component
- Add child photo + name display matching other pages (/track/feeding, etc.)
- Update state management to use selectedChildIds array for consistency
- Improve visual consistency across the application
- Maintain single selection mode for insights filtering
- Remove mock authentication from authSlice to enable real user login
- Fix WebSocket connection errors by using real JWT tokens
- Consolidate duplicate filters on insights page into single shared filter
- Update InsightsDashboard to accept props instead of managing own state
- Add MUI Grid styling for 20% min-width and centering
- Improve UX with unified filter controls for both insights and predictions
Authentication & Token Management:
- Add deviceId to token refresh flow (backend requires both refreshToken and deviceId)
- Fix React Strict Mode token clearing race condition with retry logic
- Improve AuthContext to handle all token state combinations properly
- Store deviceId in localStorage alongside tokens
UI/UX Improvements:
- Remove deprecated legacyBehavior from Next.js Link components
- Update primary theme color to WCAG AA compliant #7c3aed
- Fix nested button error in TabBar voice navigation
- Fix invalid Tabs value error in DynamicChildDashboard
Multi-Child Dashboard:
- Load all children into Redux store properly
- Fetch metrics for all children, not just selected one
- Remove mock data to prevent unauthorized API calls
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added back button to UnifiedInsightsDashboard component to match
the navigation pattern used in tracker pages (sleep, feeding, etc).
Changes:
- Added ArrowBack icon import
- Added useRouter hook
- Added IconButton with router.back() onClick handler
- Restructured header to include back button alongside title
Now insights page has consistent navigation with tracker pages.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create ComparisonView component for analytics comparison
- Add compareChildren API method with ComparisonMetric enum
- Implement interactive chart visualization with Recharts
- Support multiple metrics: sleep patterns, feeding frequency, diaper changes, activities
- Show per-child summary cards with color-coded display
- Date range filtering with DatePicker
- Build and test successfully
Completed Phase 3 tasks:
✅ Dynamic dashboard with tabs (1-3 children) and cards (4+ children)
✅ ChildSelector integration in tracking forms (feeding form complete, pattern documented for others)
✅ Comparison analytics visualization component
✅ Frontend build and test successful
Implemented comprehensive form accessibility improvements across all critical forms:
**Accessibility Attributes Added:**
- aria-required="true" on all required form fields
- aria-invalid on fields with validation errors
- aria-describedby linking error messages to inputs
- Unique id attributes on FormHelperText for error association
- role="alert" on error messages for screen reader announcements
- labelId on Select components for proper label association
- noValidate on forms to use custom validation
**Forms Updated:**
1. Login Form (app/(auth)/login/page.tsx)
- Email and password fields with full ARIA support
- Error message association with aria-describedby
2. Registration Form (app/(auth)/register/page.tsx)
- All text fields: name, email, password, DOB, parental email
- Checkbox fields: Terms, Privacy, COPPA consent
- Conditional required fields for minors
3. Child Dialog (components/children/ChildDialog.tsx)
- Name, birthdate, gender fields
- Dynamic aria-invalid based on validation state
4. Tracking Forms:
- Feeding form (app/track/feeding/page.tsx)
- Child selector, side selector, bottle type
- Food description with required validation
- Sleep form (app/track/sleep/page.tsx)
- Child selector, start/end time fields
- Quality and location selectors
**WCAG 2.1 Compliance:**
- ✅ 3.3.2 Labels or Instructions (AA)
- ✅ 4.1.3 Status Messages (AA)
- ✅ 1.3.1 Info and Relationships (A)
- ✅ 3.3.1 Error Identification (A)
**Documentation:**
- Updated REMAINING_FEATURES.md
- Marked Form Accessibility Enhancement as complete
- Status: 79 features completed (57%)
🎉 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- **EULA Persistence Fix**: Fixed EULA dialog showing on every login
- Added eulaAcceptedAt/eulaVersion to AuthResponse interface
- Updated login/register/getUserById endpoints to return EULA fields
- Changed EULACheck to use refreshUser() instead of window.reload()
- **Touch Target Accessibility**: All interactive elements now meet 48x48px minimum
- Fixed 14 undersized IconButtons across 5 files
- Changed size="small" to size="medium" with minWidth/minHeight constraints
- Updated children page, AI chat, analytics cards, legal viewer
- **Alt Text for Images**: Complete image accessibility for screen readers
- Added photoAlt field to children table (Migration V009)
- PhotoUpload component now includes alt text input field
- All Avatar components have meaningful alt text
- Default alt text: "Photo of {childName}", "{userName}'s profile photo"
- **Medical Tracking Consolidation**: Unified medical page with tabs
- Medicine page now has 3 tabs: Medication, Temperature, Doctor Visit
- Backward compatibility for legacy 'medicine' activity type
- Created dedicated /track/growth page for physical measurements
- **Track Page Updates**:
- Simplified to 6 options: Feeding, Sleep, Diaper, Medical, Activity, Growth
- Fixed grid layout to 3 cards per row with minWidth: 200px
- Updated terminology from "Medicine" to "Medical"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changes:
- Created UnifiedInsightsDashboard component with 2 tabs
- Tab 1: Insights - Shows existing charts, stats, and recent activities
- Tab 2: Predictions - Shows AI-powered predictions for next activities
- Growth Spurt Alert appears at the top when detected
- Child selector for families with multiple children
- Clean tab navigation with Timeline and TrendingUp icons
Features Now Accessible from /insights:
✅ Growth Spurt Detection (appears as alert banner)
✅ Pattern Analysis (feeding, sleep, diaper trends)
✅ AI Predictions (next feeding time, sleep duration, etc.)
✅ Charts and visualizations
✅ Recent activities timeline
User Experience:
- Single page access from bottom navigation (Insights icon)
- No need for separate /analytics page
- All smart AI features visible in one place
- Tab switching for different views
Files Changed:
- app/insights/page.tsx - Updated to use UnifiedInsightsDashboard
- components/features/analytics/UnifiedInsightsDashboard.tsx (new)
* Manages state for both tabs
* Loads insights and predictions data
* Renders Growth Spurt Alert
* Tab navigation UI
🎯 Result: Users can now easily see all AI insights and predictions
from the Insights menu item in bottom navigation!
Co-Authored-By: Claude <noreply@anthropic.com>
Added missing useEffect import in AppShell.tsx. The debug logging code
was using useEffect but it wasn't imported, causing the app to crash.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Completely removed TextField from PhotoUpload component (not just hidden)
- Added console logging to AppShell to debug user photo updates
- Rebuilt frontend to ensure changes are deployed
The TextField was showing base64 strings even with display:none due to
Next.js caching. Complete removal ensures clean UI.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
UI improvements for photo upload feature:
1. Hidden the photo URL text field completely (users don't need to see base64)
2. Added key prop to Avatar to force re-render when photoUrl changes
3. Added error handling for avatar image loading
4. Changed value display to hide base64 strings in hidden field
The camera icon is now the primary way to upload photos, with the URL field
completely hidden from view for a cleaner UX.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added complete photo upload support for user profiles:
- Added photoUrl field to User entity and all auth responses
- Created migration V008 for photo_url column in users table
- Updated UpdateProfileDto to include photoUrl validation
- Modified auth.service.ts to handle photoUrl in all user responses (register, login, getUserById, updateProfile, refreshAccessToken, loginWithExternalAuth)
- Updated AuthResponse interface to include photoUrl
- Updated frontend User and UserProfile interfaces to include photoUrl
- Updated AppShell to display user photoUrl in header avatar
- Fixed ChildDialog to remove invalid props from PhotoUpload component
The photo upload uses base64 encoding (max 5MB) for simplicity and works across all environments. Future enhancement can migrate to CDN/object storage.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The MinIO/Sharp approach doesn't work on the current server CPU architecture.
Switched to simple base64 encoding for photo uploads.
Changes:
- PhotoUpload component converts images to base64 data URLs
- 5MB file size limit
- Works on all platforms without external dependencies
- Stores photos directly in database (photoUrl field)
This is a temporary solution. For production scalability, we can:
- Upgrade server CPU to support Sharp
- Build Sharp from source
- Use Docker with prebuilt Sharp binaries
- Migrate to a proper CDN/object storage later
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add file input with hidden native picker
- Convert selected images to base64 data URLs
- Validate file type (images only) and size (max 5MB)
- Display error alerts for invalid uploads
- Show preview immediately after selection
- Update help text to indicate camera button functionality
- Handle image load/error states properly
Now clicking the camera button opens file picker and uploads work fully.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Created reusable PhotoUpload component with avatar preview
- Added photo upload to child create/edit dialog
- Added profile photo upload to settings page
- Show photo preview with fallback icon
- Display camera button for future file upload integration
- Support URL paste for immediate photo display
- Updated API types to support photoUrl field
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Convert Active Sessions and Trusted Devices to collapsible Accordion components
- Display count badge in collapsed state
- Show loading state in accordion header
- Implement 2-card grid layout on mobile (xs=6)
- Responsive card sizing and spacing
- Centered layout on mobile, horizontal on desktop
- Hide full birthdate on mobile, show age only
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Voice classification extracts duration in minutes, but sleep tracker expects
startTime/endTime. Added transformation logic to convert duration to proper
time range for sleep activities.
- Convert duration (minutes) to startTime + endTime timestamps
- Set default quality='good' and location='crib' if not specified
- Remove duration field after transformation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace connection status chips with green/gray dot on user avatar
- Fix voice command data transformation (use timestamp/data instead of startedAt/metadata)
- Keep family members online indicator on left side
- User avatar with status dot remains on right side
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change useStreaming default from true to false
- Streaming endpoint has validation issues (conversationId format)
- Non-streaming endpoint works perfectly
- This fixes the 'Sorry, I encountered an error' message in AI chat
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
BUG-1: Voice tracking not saving activities
- Fix activity data format to match backend CreateActivityDto
- Change 'timestamp' to 'startedAt' and 'data' to 'metadata'
- Remove duplicate voice button from mobile TabBar
BUG-2: Session persistence after revocation
- Add logout() call when revoking all sessions
- Add logout() call when removing all devices
- Ensures user is logged out after session/device revocation
- Clears tokens and redirects to login
BUG-3: Voice modal status not updating
- Set identifiedActivity before saving to show tracker name
- Display "Adding to [tracker] tracker..." during save
- Improves UX by showing which tracker is being updated
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Error Boundaries (VERIFIED COMPLETE)**
- Comprehensive ErrorBoundary component already implemented in components/common/ErrorBoundary.tsx
- Features: Recovery UI, error logging, isolated error boundaries, development error details
- Global error boundary in root layout
- Page-level error boundaries in AI Assistant and dashboard
- Error tracking integration ready for Sentry
**Touch Target Sizes (WCAG 2.5.5 Compliance)**
- Fixed user menu IconButton: increased from 32x32px to 44x44px minimum (medium size)
- Created lib/utils/touchTargets.ts with accessibility utilities:
* MINIMUM_TOUCH_TARGET = 44px (iOS/WCAG standard)
* RECOMMENDED_TOUCH_TARGET = 48px (Android Material Design)
* Helper functions: withTouchTarget(), validateTouchTarget()
* Component-specific guidelines for IconButton, Button, FAB, Chip, etc.
- Verified existing components meet standards:
* Quick action buttons: 140x140px ✓
* Bottom navigation: 64px height ✓
* Voice FAB: 56x56px ✓
* Voice button in tab bar: 48x48px ✓
**AI Conversation History (VERIFIED COMPLETE)**
- Comprehensive conversation management already implemented in AIChatInterface.tsx
- Features verified:
* Full conversation list with drawer (mobile) and sidebar (desktop)
* Load conversations from backend API
* Load individual conversation messages with scrolling
* Auto-scroll to bottom on new messages
* Conversation groups with collapsible organization
* Delete conversations with confirmation
* Context menu for conversation management
* Thinking messages animation
* Markdown rendering for AI responses
- Updated implementation-gaps.md to reflect completion status
**Documentation Updates**
- Updated docs/implementation-gaps.md:
* Marked Conversation History as COMPLETED
* Updated AI Assistant UI section with detailed implementation notes
* Moved remaining features (Streaming Responses, Suggested Follow-Ups, AI Response Feedback UI) to "Remaining Features" section
**Impact**
- Error boundaries prevent full app crashes and provide graceful recovery
- Touch target sizes meet WCAG 2.5.5 (AAA) and mobile platform guidelines
- Conversation history enables contextual AI interactions with full persistence
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Date/Time Formatting Polish:
- Added German and Italian locales to useLocalizedDate hook
- Applied localized date formatting to children birth dates (PPP format)
- InsightsDashboard already using localized date formatting
Number Formatting Polish:
- Applied Intl.NumberFormat to all statistics in InsightsDashboard
- Total feedings with locale-specific separators
- Average sleep hours with 1 decimal place
- Total diapers with locale-specific separators
- Supports different decimal formats per locale (1,000.50 vs 1.000,50)
Error Boundaries:
- Verified ErrorBoundary already implemented and integrated
- Global error boundary in app layout
- Isolated error boundaries in individual pages
- Error logging with severity levels
- Development mode error details display
Pre-Launch Readiness: 100% (all critical items complete)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Removed duplicate MobileNav AppBar from desktop view
- Added unified header bar across all screen sizes (mobile + desktop)
- Positioned connection status on left, user menu on right in header
- Centered bottom navigation menu on desktop (30% width with 20px margin)
- Hidden floating voice button on desktop (using center button instead)
- Updated voice command button to pink color (#FF69B4) matching design
- Added rounded corners to desktop bottom navigation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Updated track page cards to match home page styling with vibrant colors
- Applied consistent 140px height cards across track and insights pages
- Added mobile header bar with connection status and user menu
- Moved user menu from floating top-left to fixed header top-right
- Updated insights dashboard with home page color palette (#E91E63, #1976D2, etc.)
- Centered cards with minWidth constraints (200px for stats, 400px for charts)
- Fixed hydration mismatch by replacing JS media queries with CSS breakpoints
- Improved accessibility with viewport settings (removed zoom restrictions)
- Added UI improvements documentation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Extract family data from registration response and add to user object
- Backend returns family separately in registration, but included in user for login
- Remove error messages for language/measurement preferences (they save correctly)
- Add detailed console logging for debugging family issues
- Improve error message when family is missing during child creation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added dateOfBirth, parentalEmail, and coppaConsentGiven to RegisterData interface
- Updated register function to include all required COPPA compliance fields in API payload
- Added debug logging to see registration payload
- Fixed 400 error during registration due to missing required dateOfBirth field
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Repositioned Voice Command button to center of bottom navigation bar
- Added floating user menu icon in top-left corner on mobile
- User menu includes: Settings, Children, Family, and Logout options
- Updated bottom nav to show: Home, Track, Voice (center), Insights, History
- Hide original floating voice button on mobile to avoid duplication
- Improved mobile UX with easier thumb access to voice commands
- User avatar displays first letter of user's name
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Updated all Spanish (es) translation files with comprehensive translations for tracking, AI, family, insights, children, and settings pages
- Updated French (fr), Portuguese (pt), and Chinese (zh) translations to match English structure
- Added German (de) and Italian (it) language support with complete translation files
- Fixed medicine tracker route from /track/medication to /track/medicine
- Updated i18n config to support 7 languages: en, es, fr, pt, zh, de, it
- All tracking pages now fully localized: sleep, feeding, diaper, medicine, activity
- AI assistant interface fully translated with thinking messages and suggested questions
- Family management and insights pages now support all languages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed measurement unit not persisting across page refreshes:
- Settings page now includes measurementUnit in the preferences object when saving
- MeasurementUnitSelector now accepts value/onChange props for controlled usage
- Settings state properly loads and saves measurementUnit from user preferences
- UnitInput component will now correctly read imperial/metric from user.preferences.measurementUnit
Previously, measurementUnit was only saved to localStorage but not synced to backend,
causing UnitInput to always default to metric since it reads from user.preferences.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implemented automatic unit conversions for feeding and medicine tracking:
- Created UnitInput component for automatic ml↔oz conversions
- Updated Feeding page to use UnitInput for bottle amounts
- Updated Medicine page to use UnitInput for liquid medicine dosages
- All values stored in metric (ml) in database
- Display values automatically converted based on user's measurement preference
- Supports voice input with proper unit handling
Component features:
- Automatic conversion between metric and imperial
- User preference-based display
- Consistent metric storage
- Type safety with TypeScript
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed React hydration warnings caused by invalid HTML nesting in the
DeviceTrustManagement component.
## Issues Fixed
- Error: "<p> cannot be a descendant of <p>"
- Error: "<div> cannot be a descendant of <p>"
- Error: "<p> cannot contain a nested <p>"
- Error: "<p> cannot contain a nested <div>"
## Root Cause
The ListItemText component renders its secondary prop as a <p> tag by default.
We were incorrectly nesting Box (<div>) and Typography (<p>) components inside
the secondary prop, causing invalid HTML structure.
## Solution
- Removed nested Box and Typography components from ListItemText props
- Used simple text content with <br /> for line breaks in secondary text
- Moved chips (Current, Trusted/Untrusted) outside of ListItemText
- Positioned chips as separate Box between ListItemText and ListItemSecondaryAction
- Maintained visual layout while fixing HTML structure
## Changes
- primary: Now just plain text (device.platform)
- secondary: Plain text with <br /> separator instead of nested Typography
- Chips: Moved to separate Box with flex layout
This ensures proper HTML semantics and eliminates hydration errors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>