feat: Add enhanced analytics dashboard with advanced visualizations
Some checks failed
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled

- 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>
This commit is contained in:
2025-10-06 13:17:20 +00:00
parent b0ac2f71df
commit 19e50a3b75
13 changed files with 1317 additions and 223 deletions

View File

@@ -41,6 +41,7 @@ export default function AdvancedAnalyticsPage() {
const [selectedChildId, setSelectedChildId] = useState<string>('');
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string>('');
const [activeTab, setActiveTab] = useState(0);
// Analytics data states
const [circadianData, setCircadianData] = useState<CircadianRhythm | null>(null);
@@ -259,19 +260,16 @@ export default function AdvancedAnalyticsPage() {
Select Child:
</label>
<Select
id="child-select"
value={selectedChildId}
onValueChange={setSelectedChildId}
onChange={(e) => setSelectedChildId(e.target.value as string)}
sx={{ minWidth: 200 }}
>
<SelectTrigger className="w-[200px]">
<SelectValue placeholder="Select a child" />
</SelectTrigger>
<SelectContent>
{children.map((child) => (
<SelectItem key={child.id} value={child.id}>
{child.name}
</SelectItem>
))}
</SelectContent>
{children.map((child) => (
<MenuItem key={child.id} value={child.id}>
{child.name}
</MenuItem>
))}
</Select>
</div>
</CardContent>
@@ -285,79 +283,91 @@ export default function AdvancedAnalyticsPage() {
)}
{/* Analytics Tabs */}
<Tabs defaultValue="circadian" className="w-full">
<TabsList className="grid w-full grid-cols-5">
<TabsTrigger value="circadian">
<Brain className="h-4 w-4 mr-2" />
Sleep Rhythm
</TabsTrigger>
<TabsTrigger value="anomalies">
<Activity className="h-4 w-4 mr-2" />
Anomalies
</TabsTrigger>
<TabsTrigger value="growth">
<Baby className="h-4 w-4 mr-2" />
Growth
</TabsTrigger>
<TabsTrigger value="correlations">
<Link className="h-4 w-4 mr-2" />
Correlations
</TabsTrigger>
<TabsTrigger value="trends">
<TrendingUp className="h-4 w-4 mr-2" />
Trends
</TabsTrigger>
</TabsList>
<TabsContent value="circadian" className="space-y-4">
<CircadianRhythmCard
data={circadianData}
loading={circadianLoading}
error={circadianError}
<Box sx={{ width: '100%' }}>
<Tabs
value={activeTab}
onChange={(e, newValue) => setActiveTab(newValue)}
variant="scrollable"
scrollButtons="auto"
>
<Tab
icon={<Brain style={{ width: 16, height: 16 }} />}
iconPosition="start"
label="Sleep Rhythm"
/>
</TabsContent>
<TabsContent value="anomalies" className="space-y-4">
<AnomalyAlertsPanel
data={anomalyData}
loading={anomalyLoading}
error={anomalyError}
<Tab
icon={<Activity style={{ width: 16, height: 16 }} />}
iconPosition="start"
label="Anomalies"
/>
</TabsContent>
<TabsContent value="growth" className="space-y-4">
<GrowthPercentileChart
data={growthData}
loading={growthLoading}
error={growthError}
<Tab
icon={<Baby style={{ width: 16, height: 16 }} />}
iconPosition="start"
label="Growth"
/>
</TabsContent>
<TabsContent value="correlations" className="space-y-4">
<CorrelationInsights
data={correlationData}
loading={correlationLoading}
error={correlationError}
<Tab
icon={<Link style={{ width: 16, height: 16 }} />}
iconPosition="start"
label="Correlations"
/>
</TabsContent>
<Tab
icon={<TrendingUp style={{ width: 16, height: 16 }} />}
iconPosition="start"
label="Trends"
/>
</Tabs>
<TabsContent value="trends" className="space-y-4">
<div className="grid gap-4 md:grid-cols-2">
<TrendAnalysisChart
data={sleepTrendData}
activityType="Sleep"
loading={trendLoading}
error={trendError}
<Box sx={{ py: 3 }}>
{activeTab === 0 && (
<CircadianRhythmCard
data={circadianData}
loading={circadianLoading}
error={circadianError}
/>
<TrendAnalysisChart
data={feedingTrendData}
activityType="Feeding"
loading={trendLoading}
error={trendError}
)}
{activeTab === 1 && (
<AnomalyAlertsPanel
data={anomalyData}
loading={anomalyLoading}
error={anomalyError}
/>
</div>
</TabsContent>
</Tabs>
)}
{activeTab === 2 && (
<GrowthPercentileChart
data={growthData}
loading={growthLoading}
error={growthError}
/>
)}
{activeTab === 3 && (
<CorrelationInsights
data={correlationData}
loading={correlationLoading}
error={correlationError}
/>
)}
{activeTab === 4 && (
<div style={{ display: 'grid', gap: '1rem', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))' }}>
<TrendAnalysisChart
data={sleepTrendData}
activityType="Sleep"
loading={trendLoading}
error={trendError}
/>
<TrendAnalysisChart
data={feedingTrendData}
activityType="Feeding"
loading={trendLoading}
error={trendError}
/>
</div>
)}
</Box>
</Box>
</div>
</AppShell>
</ProtectedRoute>