- Initialize Next.js 14 web application with Material UI and TypeScript - Implement authentication (login/register) with device fingerprint - Create mobile-first responsive layout with app shell pattern - Add tracking pages for feeding, sleep, and diaper changes - Implement activity history with filtering - Configure backend CORS for web frontend (port 3030) - Update backend port to 3020, frontend to 3030 - Fix API response handling for auth endpoints 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
249 lines
8.1 KiB
TypeScript
249 lines
8.1 KiB
TypeScript
'use client';
|
||
|
||
import { useState } from 'react';
|
||
import {
|
||
Box,
|
||
Stepper,
|
||
Step,
|
||
StepLabel,
|
||
Button,
|
||
Typography,
|
||
Paper,
|
||
TextField,
|
||
Avatar,
|
||
IconButton,
|
||
Alert,
|
||
} from '@mui/material';
|
||
import { ArrowBack, ArrowForward, Check } from '@mui/icons-material';
|
||
import { motion, AnimatePresence } from 'framer-motion';
|
||
import { useRouter } from 'next/navigation';
|
||
|
||
const steps = ['Welcome', 'Add Child', 'Invite Family', 'Notifications'];
|
||
|
||
export default function OnboardingPage() {
|
||
const [activeStep, setActiveStep] = useState(0);
|
||
const [childName, setChildName] = useState('');
|
||
const [childBirthDate, setChildBirthDate] = useState('');
|
||
const router = useRouter();
|
||
|
||
const handleNext = () => {
|
||
if (activeStep === steps.length - 1) {
|
||
// Complete onboarding
|
||
router.push('/');
|
||
} else {
|
||
setActiveStep((prevActiveStep) => prevActiveStep + 1);
|
||
}
|
||
};
|
||
|
||
const handleBack = () => {
|
||
setActiveStep((prevActiveStep) => prevActiveStep - 1);
|
||
};
|
||
|
||
const handleSkip = () => {
|
||
router.push('/');
|
||
};
|
||
|
||
return (
|
||
<Box
|
||
sx={{
|
||
minHeight: '100vh',
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
px: 3,
|
||
py: 4,
|
||
background: 'linear-gradient(135deg, #FFE4E1 0%, #FFDAB9 100%)',
|
||
}}
|
||
>
|
||
<Paper
|
||
elevation={0}
|
||
sx={{
|
||
maxWidth: 600,
|
||
mx: 'auto',
|
||
width: '100%',
|
||
p: 4,
|
||
borderRadius: 4,
|
||
background: 'rgba(255, 255, 255, 0.95)',
|
||
backdropFilter: 'blur(10px)',
|
||
}}
|
||
>
|
||
<Stepper activeStep={activeStep} sx={{ mb: 4 }}>
|
||
{steps.map((label) => (
|
||
<Step key={label}>
|
||
<StepLabel>{label}</StepLabel>
|
||
</Step>
|
||
))}
|
||
</Stepper>
|
||
|
||
<AnimatePresence mode="wait">
|
||
<motion.div
|
||
key={activeStep}
|
||
initial={{ opacity: 0, x: 20 }}
|
||
animate={{ opacity: 1, x: 0 }}
|
||
exit={{ opacity: 0, x: -20 }}
|
||
transition={{ duration: 0.3 }}
|
||
>
|
||
{activeStep === 0 && (
|
||
<Box sx={{ textAlign: 'center', py: 4 }}>
|
||
<Typography variant="h4" gutterBottom fontWeight="600" color="primary.main">
|
||
Welcome to Maternal! 🎉
|
||
</Typography>
|
||
<Typography variant="body1" color="text.secondary" sx={{ mt: 2, mb: 4 }}>
|
||
We're excited to help you track and understand your child's development, sleep patterns, feeding schedules, and more.
|
||
</Typography>
|
||
<Box sx={{ display: 'flex', gap: 2, justifyContent: 'center', flexWrap: 'wrap' }}>
|
||
<Paper sx={{ p: 2, flex: 1, minWidth: 150 }}>
|
||
<Typography variant="h6" fontWeight="600">📊</Typography>
|
||
<Typography variant="body2">Track Activities</Typography>
|
||
</Paper>
|
||
<Paper sx={{ p: 2, flex: 1, minWidth: 150 }}>
|
||
<Typography variant="h6" fontWeight="600">🤖</Typography>
|
||
<Typography variant="body2">AI Insights</Typography>
|
||
</Paper>
|
||
<Paper sx={{ p: 2, flex: 1, minWidth: 150 }}>
|
||
<Typography variant="h6" fontWeight="600">👨👩👧</Typography>
|
||
<Typography variant="body2">Family Sharing</Typography>
|
||
</Paper>
|
||
</Box>
|
||
</Box>
|
||
)}
|
||
|
||
{activeStep === 1 && (
|
||
<Box sx={{ py: 4 }}>
|
||
<Typography variant="h5" gutterBottom fontWeight="600">
|
||
Add Your First Child
|
||
</Typography>
|
||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||
Let's start by adding some basic information about your child.
|
||
</Typography>
|
||
|
||
<TextField
|
||
fullWidth
|
||
label="Child's Name"
|
||
value={childName}
|
||
onChange={(e) => setChildName(e.target.value)}
|
||
margin="normal"
|
||
InputProps={{
|
||
sx: { borderRadius: 3 },
|
||
}}
|
||
/>
|
||
|
||
<TextField
|
||
fullWidth
|
||
label="Birth Date"
|
||
type="date"
|
||
value={childBirthDate}
|
||
onChange={(e) => setChildBirthDate(e.target.value)}
|
||
margin="normal"
|
||
InputLabelProps={{
|
||
shrink: true,
|
||
}}
|
||
InputProps={{
|
||
sx: { borderRadius: 3 },
|
||
}}
|
||
/>
|
||
|
||
<Alert severity="info" sx={{ mt: 3, borderRadius: 2 }}>
|
||
You can add more children and details later from settings.
|
||
</Alert>
|
||
</Box>
|
||
)}
|
||
|
||
{activeStep === 2 && (
|
||
<Box sx={{ py: 4 }}>
|
||
<Typography variant="h5" gutterBottom fontWeight="600">
|
||
Invite Family Members
|
||
</Typography>
|
||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||
Share your child's progress with family members. They can view activities and add their own entries.
|
||
</Typography>
|
||
|
||
<TextField
|
||
fullWidth
|
||
label="Email Address"
|
||
type="email"
|
||
margin="normal"
|
||
placeholder="partner@example.com"
|
||
InputProps={{
|
||
sx: { borderRadius: 3 },
|
||
}}
|
||
/>
|
||
|
||
<Button
|
||
variant="outlined"
|
||
fullWidth
|
||
sx={{ mt: 2 }}
|
||
>
|
||
Send Invitation
|
||
</Button>
|
||
|
||
<Alert severity="info" sx={{ mt: 3, borderRadius: 2 }}>
|
||
You can skip this step and invite family members later.
|
||
</Alert>
|
||
</Box>
|
||
)}
|
||
|
||
{activeStep === 3 && (
|
||
<Box sx={{ textAlign: 'center', py: 4 }}>
|
||
<Avatar
|
||
sx={{
|
||
width: 80,
|
||
height: 80,
|
||
bgcolor: 'primary.main',
|
||
mx: 'auto',
|
||
mb: 3,
|
||
}}
|
||
>
|
||
<Check sx={{ fontSize: 48 }} />
|
||
</Avatar>
|
||
<Typography variant="h5" gutterBottom fontWeight="600">
|
||
You're All Set! 🎉
|
||
</Typography>
|
||
<Typography variant="body1" color="text.secondary" sx={{ mb: 4 }}>
|
||
Start tracking your child's activities and get personalized insights.
|
||
</Typography>
|
||
|
||
<Paper sx={{ p: 3, bgcolor: 'primary.light', mb: 3 }}>
|
||
<Typography variant="body2" fontWeight="600" gutterBottom>
|
||
Next Steps:
|
||
</Typography>
|
||
<Typography variant="body2" align="left" component="div">
|
||
• Track your first feeding, sleep, or diaper change<br />
|
||
• Chat with our AI assistant for parenting tips<br />
|
||
• Explore insights and predictions based on your data
|
||
</Typography>
|
||
</Paper>
|
||
</Box>
|
||
)}
|
||
</motion.div>
|
||
</AnimatePresence>
|
||
|
||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mt: 4 }}>
|
||
<Button
|
||
onClick={handleBack}
|
||
disabled={activeStep === 0}
|
||
startIcon={<ArrowBack />}
|
||
>
|
||
Back
|
||
</Button>
|
||
|
||
<Box sx={{ flex: 1 }} />
|
||
|
||
{activeStep < steps.length - 1 && activeStep > 0 && (
|
||
<Button onClick={handleSkip} sx={{ mr: 2 }}>
|
||
Skip
|
||
</Button>
|
||
)}
|
||
|
||
<Button
|
||
variant="contained"
|
||
onClick={handleNext}
|
||
endIcon={activeStep === steps.length - 1 ? <Check /> : <ArrowForward />}
|
||
>
|
||
{activeStep === steps.length - 1 ? 'Get Started' : 'Next'}
|
||
</Button>
|
||
</Box>
|
||
</Paper>
|
||
</Box>
|
||
);
|
||
}
|