docs: Add comprehensive multi-child implementation plan
Added detailed implementation plan covering: - Frontend: Dynamic UI, child selector, bulk activity logging, comparison analytics - Backend: Bulk operations, multi-child queries, family statistics - AI/Voice: Child name detection, context building, clarification flows - Database: Schema enhancements, user preferences, bulk operation tracking - State management, API enhancements, real-time sync updates - Testing strategy: Unit, integration, and E2E tests - Migration plan with feature flags for phased rollout - Performance optimizations: Caching, indexes, code splitting Also includes: - Security fixes for multi-family data leakage in analytics pages - ParentFlow branding updates - Activity tracking navigation improvements - Backend DTO and error handling fixes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,9 @@ import {
|
||||
FormControlLabel,
|
||||
FormControl,
|
||||
Grid,
|
||||
StepConnector,
|
||||
stepConnectorClasses,
|
||||
styled,
|
||||
} from '@mui/material';
|
||||
import { ArrowBack, ArrowForward, Check, Language, Straighten } from '@mui/icons-material';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
@@ -33,9 +36,60 @@ import { useLocale, MeasurementSystem } from '@/hooks/useLocale';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { supportedLanguages } from '@/lib/i18n/config';
|
||||
import { usersApi } from '@/lib/api/users';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { StepIconProps } from '@mui/material/StepIcon';
|
||||
|
||||
const steps = ['Welcome', 'Language', 'Measurements', 'Add Child', 'Complete'];
|
||||
|
||||
// Custom connector for mobile-friendly stepper
|
||||
const CustomConnector = styled(StepConnector)(({ theme }) => ({
|
||||
[`&.${stepConnectorClasses.active}`]: {
|
||||
[`& .${stepConnectorClasses.line}`]: {
|
||||
borderColor: theme.palette.primary.main,
|
||||
},
|
||||
},
|
||||
[`&.${stepConnectorClasses.completed}`]: {
|
||||
[`& .${stepConnectorClasses.line}`]: {
|
||||
borderColor: theme.palette.primary.main,
|
||||
},
|
||||
},
|
||||
[`& .${stepConnectorClasses.line}`]: {
|
||||
borderColor: theme.palette.divider,
|
||||
borderTopWidth: 2,
|
||||
borderRadius: 1,
|
||||
},
|
||||
}));
|
||||
|
||||
// Custom step icon showing numbers
|
||||
const CustomStepIconRoot = styled('div')<{ ownerState: { active?: boolean; completed?: boolean } }>(
|
||||
({ theme, ownerState }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: ownerState.completed
|
||||
? theme.palette.primary.main
|
||||
: ownerState.active
|
||||
? theme.palette.primary.main
|
||||
: theme.palette.grey[300],
|
||||
color: ownerState.active || ownerState.completed ? '#fff' : theme.palette.text.secondary,
|
||||
fontWeight: 600,
|
||||
fontSize: '0.875rem',
|
||||
})
|
||||
);
|
||||
|
||||
function CustomStepIcon(props: StepIconProps) {
|
||||
const { active, completed, icon } = props;
|
||||
|
||||
return (
|
||||
<CustomStepIconRoot ownerState={{ active, completed }}>
|
||||
{completed ? <Check sx={{ fontSize: 18 }} /> : icon}
|
||||
</CustomStepIconRoot>
|
||||
);
|
||||
}
|
||||
|
||||
export default function OnboardingPage() {
|
||||
const [activeStep, setActiveStep] = useState(0);
|
||||
const [selectedLanguage, setSelectedLanguage] = useState('en');
|
||||
@@ -49,6 +103,7 @@ export default function OnboardingPage() {
|
||||
const { user, refreshUser } = useAuth();
|
||||
const { setLanguage, setMeasurementSystem } = useLocale();
|
||||
const { t } = useTranslation('onboarding');
|
||||
const theme = useTheme();
|
||||
|
||||
const handleNext = async () => {
|
||||
setError('');
|
||||
@@ -154,7 +209,7 @@ export default function OnboardingPage() {
|
||||
flexDirection: 'column',
|
||||
px: 3,
|
||||
py: 4,
|
||||
background: 'linear-gradient(135deg, #FFE4E1 0%, #FFDAB9 100%)',
|
||||
background: `linear-gradient(135deg, ${theme.palette.primary.light} 0%, ${theme.palette.secondary.light} 100%)`,
|
||||
}}
|
||||
>
|
||||
<Paper
|
||||
@@ -163,13 +218,18 @@ export default function OnboardingPage() {
|
||||
maxWidth: 600,
|
||||
mx: 'auto',
|
||||
width: '100%',
|
||||
p: 4,
|
||||
p: { xs: 3, sm: 4 },
|
||||
borderRadius: 4,
|
||||
background: 'rgba(255, 255, 255, 0.95)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
}}
|
||||
>
|
||||
<Stepper activeStep={activeStep} sx={{ mb: 4 }}>
|
||||
<Stepper
|
||||
activeStep={activeStep}
|
||||
alternativeLabel
|
||||
connector={<CustomConnector />}
|
||||
sx={{ mb: 4 }}
|
||||
>
|
||||
{steps.map((label, index) => {
|
||||
let stepLabel = label;
|
||||
if (index === 0) stepLabel = t('welcome.title').split('!')[0];
|
||||
@@ -177,10 +237,24 @@ export default function OnboardingPage() {
|
||||
else if (index === 2) stepLabel = t('measurements.title');
|
||||
else if (index === 3) stepLabel = t('child.title');
|
||||
else if (index === 4) stepLabel = t('complete.title').split('!')[0];
|
||||
|
||||
|
||||
// Only show label for active step on mobile
|
||||
const showLabel = activeStep === index;
|
||||
|
||||
return (
|
||||
<Step key={label}>
|
||||
<StepLabel>{stepLabel}</StepLabel>
|
||||
<StepLabel
|
||||
StepIconComponent={CustomStepIcon}
|
||||
sx={{
|
||||
'& .MuiStepLabel-label': {
|
||||
display: { xs: showLabel ? 'block' : 'none', sm: 'block' },
|
||||
mt: 1,
|
||||
fontSize: { xs: '0.75rem', sm: '0.875rem' },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{stepLabel}
|
||||
</StepLabel>
|
||||
</Step>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user