Implement Phase 7 Performance Optimization and fix tracking system
Phase 7 Implementation: - Add lazy loading for AI Assistant and Insights pages - Create LoadingFallback component with skeleton screens (page, card, list, chart, chat variants) - Create OptimizedImage component with Next.js Image optimization - Create PerformanceMonitor component with web-vitals v5 integration - Add performance monitoring library tracking Core Web Vitals (CLS, INP, FCP, LCP, TTFB) - Install web-vitals v5.1.0 dependency - Extract AI chat interface and insights dashboard to lazy-loaded components Tracking System Fixes: - Fix API data transformation between frontend (timestamp/data) and backend (startedAt/metadata) - Update createActivity, getActivities, and getActivity to properly transform data structures - Fix diaper, feeding, and sleep tracking pages to work with backend API Homepage Improvements: - Connect Today's Summary to backend daily summary API - Load real-time data for feeding count, sleep hours, and diaper count - Add loading states and empty states for better UX - Format sleep duration as "Xh Ym" for better readability - Display child name in summary section 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
77
maternal-web/components/common/OptimizedImage.tsx
Normal file
77
maternal-web/components/common/OptimizedImage.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import { useState } from 'react';
|
||||
import Image, { ImageProps } from 'next/image';
|
||||
import { Box, Skeleton } from '@mui/material';
|
||||
|
||||
interface OptimizedImageProps extends Omit<ImageProps, 'onLoadingComplete'> {
|
||||
onLoadComplete?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* OptimizedImage Component
|
||||
*
|
||||
* Wraps Next.js Image component with:
|
||||
* - Loading states with MUI Skeleton
|
||||
* - Blur placeholder support
|
||||
* - Loading completion events
|
||||
* - Automatic optimization
|
||||
*/
|
||||
export const OptimizedImage: React.FC<OptimizedImageProps> = ({
|
||||
src,
|
||||
alt,
|
||||
width,
|
||||
height,
|
||||
onLoadComplete,
|
||||
style,
|
||||
...props
|
||||
}) => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const handleLoadingComplete = () => {
|
||||
setIsLoading(false);
|
||||
onLoadComplete?.();
|
||||
};
|
||||
|
||||
// Generate a simple blur data URL for placeholder
|
||||
const blurDataURL = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgZmlsbD0iI2YwZjBmMCIvPjwvc3ZnPg==';
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'relative',
|
||||
width: typeof width === 'number' ? `${width}px` : width,
|
||||
height: typeof height === 'number' ? `${height}px` : height,
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
{isLoading && (
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
width={width}
|
||||
height={height}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
borderRadius: 'inherit',
|
||||
}}
|
||||
animation="wave"
|
||||
/>
|
||||
)}
|
||||
<Image
|
||||
src={src}
|
||||
alt={alt}
|
||||
width={width}
|
||||
height={height}
|
||||
onLoadingComplete={handleLoadingComplete}
|
||||
placeholder="blur"
|
||||
blurDataURL={blurDataURL}
|
||||
style={{
|
||||
opacity: isLoading ? 0 : 1,
|
||||
transition: 'opacity 0.3s ease-in-out',
|
||||
...style,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user