Add skeleton loading states across all tracking pages
- Replace CircularProgress spinners with content-aware skeleton screens - Add FormSkeleton for form loading states (feeding, sleep, diaper pages) - Add ActivityListSkeleton for recent activities loading - Improves perceived performance with layout-matching placeholders 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ import { AppShell } from '@/components/layouts/AppShell/AppShell';
|
||||
import { ProtectedRoute } from '@/components/common/ProtectedRoute';
|
||||
import { ErrorBoundary } from '@/components/common/ErrorBoundary';
|
||||
import { ChartErrorFallback } from '@/components/common/ErrorFallbacks';
|
||||
import { StatGridSkeleton, ChartSkeleton } from '@/components/common/LoadingSkeletons';
|
||||
import {
|
||||
TrendingUp,
|
||||
Hotel,
|
||||
@@ -102,15 +103,14 @@ export default function AnalyticsPage() {
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<AppShell>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
minHeight: '60vh',
|
||||
}}
|
||||
>
|
||||
<CircularProgress />
|
||||
<Box>
|
||||
<Typography variant="h4" gutterBottom fontWeight="600" sx={{ mb: 3 }}>
|
||||
Analytics & Insights
|
||||
</Typography>
|
||||
<StatGridSkeleton count={3} />
|
||||
<Box sx={{ mt: 4 }}>
|
||||
<ChartSkeleton height={350} />
|
||||
</Box>
|
||||
</Box>
|
||||
</AppShell>
|
||||
</ProtectedRoute>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { EmailVerificationBanner } from '@/components/common/EmailVerificationBa
|
||||
import { ErrorBoundary } from '@/components/common/ErrorBoundary';
|
||||
import { DataErrorFallback } from '@/components/common/ErrorFallbacks';
|
||||
import { NetworkStatusIndicator } from '@/components/common/NetworkStatusIndicator';
|
||||
import { StatGridSkeleton } from '@/components/common/LoadingSkeletons';
|
||||
import {
|
||||
Restaurant,
|
||||
Hotel,
|
||||
@@ -147,12 +148,11 @@ export default function HomePage() {
|
||||
isolate
|
||||
fallback={<DataErrorFallback error={new Error('Failed to load summary')} />}
|
||||
>
|
||||
<Paper sx={{ p: 3 }}>
|
||||
{loading ? (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 4 }}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
) : !dailySummary ? (
|
||||
{loading ? (
|
||||
<StatGridSkeleton count={3} />
|
||||
) : (
|
||||
<Paper sx={{ p: 3 }}>
|
||||
{!dailySummary ? (
|
||||
<Box sx={{ textAlign: 'center', py: 4 }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{children.length === 0
|
||||
@@ -198,8 +198,9 @@ export default function HomePage() {
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</Paper>
|
||||
)}
|
||||
</Paper>
|
||||
)}
|
||||
</ErrorBoundary>
|
||||
|
||||
{/* Next Predicted Activity */}
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
ToggleButton,
|
||||
FormLabel,
|
||||
} from '@mui/material';
|
||||
import { FormSkeleton, ActivityListSkeleton } from '@/components/common/LoadingSkeletons';
|
||||
import {
|
||||
ArrowBack,
|
||||
Refresh,
|
||||
@@ -305,8 +306,17 @@ export default function DiaperTrackPage() {
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<AppShell>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 8 }}>
|
||||
<CircularProgress />
|
||||
<Box>
|
||||
<Typography variant="h4" fontWeight="600" sx={{ mb: 3 }}>
|
||||
Track Diaper Change
|
||||
</Typography>
|
||||
<Paper sx={{ p: 3, mb: 3 }}>
|
||||
<FormSkeleton />
|
||||
</Paper>
|
||||
<Typography variant="h6" fontWeight="600" sx={{ mb: 2 }}>
|
||||
Recent Diaper Changes
|
||||
</Typography>
|
||||
<ActivityListSkeleton count={3} />
|
||||
</Box>
|
||||
</AppShell>
|
||||
</ProtectedRoute>
|
||||
@@ -545,9 +555,7 @@ export default function DiaperTrackPage() {
|
||||
</Box>
|
||||
|
||||
{diapersLoading ? (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 4 }}>
|
||||
<CircularProgress size={30} />
|
||||
</Box>
|
||||
<ActivityListSkeleton count={3} />
|
||||
) : recentDiapers.length === 0 ? (
|
||||
<Box sx={{ textAlign: 'center', py: 4 }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
|
||||
@@ -49,6 +49,7 @@ import { useAuth } from '@/lib/auth/AuthContext';
|
||||
import { trackingApi, Activity } from '@/lib/api/tracking';
|
||||
import { childrenApi, Child } from '@/lib/api/children';
|
||||
import { VoiceInputButton } from '@/components/voice/VoiceInputButton';
|
||||
import { FormSkeleton, ActivityListSkeleton } from '@/components/common/LoadingSkeletons';
|
||||
import { motion } from 'framer-motion';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
|
||||
@@ -308,8 +309,17 @@ function FeedingTrackPage() {
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<AppShell>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 8 }}>
|
||||
<CircularProgress />
|
||||
<Box>
|
||||
<Typography variant="h4" fontWeight="600" sx={{ mb: 3 }}>
|
||||
Track Feeding
|
||||
</Typography>
|
||||
<Paper sx={{ p: 3, mb: 3 }}>
|
||||
<FormSkeleton />
|
||||
</Paper>
|
||||
<Typography variant="h6" fontWeight="600" sx={{ mb: 2 }}>
|
||||
Recent Feedings
|
||||
</Typography>
|
||||
<ActivityListSkeleton count={3} />
|
||||
</Box>
|
||||
</AppShell>
|
||||
</ProtectedRoute>
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
Chip,
|
||||
Snackbar,
|
||||
} from '@mui/material';
|
||||
import { FormSkeleton, ActivityListSkeleton } from '@/components/common/LoadingSkeletons';
|
||||
import {
|
||||
ArrowBack,
|
||||
Refresh,
|
||||
@@ -320,8 +321,17 @@ export default function SleepTrackPage() {
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<AppShell>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 8 }}>
|
||||
<CircularProgress />
|
||||
<Box>
|
||||
<Typography variant="h4" fontWeight="600" sx={{ mb: 3 }}>
|
||||
Track Sleep
|
||||
</Typography>
|
||||
<Paper sx={{ p: 3, mb: 3 }}>
|
||||
<FormSkeleton />
|
||||
</Paper>
|
||||
<Typography variant="h6" fontWeight="600" sx={{ mb: 2 }}>
|
||||
Recent Sleep Activities
|
||||
</Typography>
|
||||
<ActivityListSkeleton count={3} />
|
||||
</Box>
|
||||
</AppShell>
|
||||
</ProtectedRoute>
|
||||
@@ -536,9 +546,7 @@ export default function SleepTrackPage() {
|
||||
</Box>
|
||||
|
||||
{sleepsLoading ? (
|
||||
<Box sx={{ display: 'flex', justifyContent: 'center', py: 4 }}>
|
||||
<CircularProgress size={30} />
|
||||
</Box>
|
||||
<ActivityListSkeleton count={3} />
|
||||
) : recentSleeps.length === 0 ? (
|
||||
<Box sx={{ textAlign: 'center', py: 4 }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
|
||||
Reference in New Issue
Block a user