import { useEffect, useState } from 'react' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Progress } from '@/components/ui/progress' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Memory } from '@/types' import { formatDistanceToNow } from '@/utils/helpers' interface StatisticsDashboardProps { memories: Memory[] } interface MemoryStats { total: number categories: Record projects: Record tags: Record contentTypes: Record complexityLevels: Record recentActivity: { today: number thisWeek: number thisMonth: number } averageSize: number largestMemory: Memory | null mostActiveProject: string | null trendingTags: string[] memoryGrowth: { date: string; count: number }[] } export function StatisticsDashboard({ memories }: StatisticsDashboardProps) { const [stats, setStats] = useState(null) const [selectedTimeRange, setSelectedTimeRange] = useState<'7d' | '30d' | '90d' | 'all'>('30d') useEffect(() => { if (memories.length === 0) { setStats(null) return } const calculateStats = (): MemoryStats => { const now = new Date() const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()) const thisWeek = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000) const thisMonth = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000) // Filter memories by time range let filteredMemories = memories if (selectedTimeRange !== 'all') { const days = selectedTimeRange === '7d' ? 7 : selectedTimeRange === '30d' ? 30 : 90 const cutoff = new Date(now.getTime() - days * 24 * 60 * 60 * 1000) filteredMemories = memories.filter(m => new Date(m.timestamp) >= cutoff) } // Calculate categories const categories: Record = {} filteredMemories.forEach(memory => { const category = memory.category || 'uncategorized' categories[category] = (categories[category] || 0) + 1 }) // Calculate projects const projects: Record = {} filteredMemories.forEach(memory => { const project = memory.project || 'general' projects[project] = (projects[project] || 0) + 1 }) // Calculate tags const tags: Record = {} filteredMemories.forEach(memory => { if (memory.tags && Array.isArray(memory.tags)) { memory.tags.forEach(tag => { // Skip title: and summary: metadata tags if (!tag.startsWith('title:') && !tag.startsWith('summary:')) { tags[tag] = (tags[tag] || 0) + 1 } }) } }) // Calculate content types const contentTypes: Record = {} filteredMemories.forEach(memory => { const contentType = memory.metadata?.contentType || 'text' contentTypes[contentType] = (contentTypes[contentType] || 0) + 1 }) // Calculate complexity levels const complexityLevels: Record = { 1: 0, 2: 0, 3: 0, 4: 0 } filteredMemories.forEach(memory => { const complexity = (memory as any).complexity || 1 complexityLevels[complexity] = (complexityLevels[complexity] || 0) + 1 }) // Calculate recent activity const recentActivity = { today: filteredMemories.filter(m => new Date(m.timestamp) >= today).length, thisWeek: filteredMemories.filter(m => new Date(m.timestamp) >= thisWeek).length, thisMonth: filteredMemories.filter(m => new Date(m.timestamp) >= thisMonth).length } // Calculate average size const totalSize = filteredMemories.reduce((sum, memory) => sum + memory.content.length, 0) const averageSize = filteredMemories.length > 0 ? Math.round(totalSize / filteredMemories.length) : 0 // Find largest memory const largestMemory = filteredMemories.reduce((largest, memory) => !largest || memory.content.length > largest.content.length ? memory : largest , null as Memory | null) // Find most active project const mostActiveProject = Object.entries(projects).reduce((most, [project, count]) => !most || count > most[1] ? [project, count] : most , null as [string, number] | null)?.[0] || null // Calculate trending tags (top 10 by frequency) const trendingTags = Object.entries(tags) .sort(([,a], [,b]) => b - a) .slice(0, 10) .map(([tag]) => tag) // Calculate memory growth over time const memoryGrowth: { date: string; count: number }[] = [] const groupedByDate = filteredMemories.reduce((acc, memory) => { // Handle invalid timestamps gracefully const timestamp = memory.timestamp || new Date().toISOString() const dateObj = new Date(timestamp) // Skip invalid dates if (isNaN(dateObj.getTime())) { console.warn('Invalid timestamp found:', memory.timestamp, 'for memory:', memory.id) return acc } const date = dateObj.toISOString().split('T')[0] acc[date] = (acc[date] || 0) + 1 return acc }, {} as Record) // Create time series data const sortedDates = Object.keys(groupedByDate).sort() let cumulativeCount = 0 sortedDates.forEach(date => { cumulativeCount += groupedByDate[date] memoryGrowth.push({ date, count: cumulativeCount }) }) return { total: filteredMemories.length, categories, projects, tags, contentTypes, complexityLevels, recentActivity, averageSize, largestMemory, mostActiveProject, trendingTags, memoryGrowth } } setStats(calculateStats()) }, [memories, selectedTimeRange]) if (!stats || memories.length === 0) { return (
📊

No Data Yet

Start adding memories to see analytics and insights!

) } const getCategoryIcon = (category: string) => { const icons: Record = { personal: '👤', work: '💼', code: '💻', research: '🔬', conversations: '💬', preferences: '⚙️', uncategorized: '📄' } return icons[category] || '📄' } const getComplexityIcon = (level: number) => { const icons = ['🟢', '🟡', '🟠', '🔴'] return icons[level - 1] || '⚪' } return (
{/* Time Range Filter */}

🎉 SHADCN UI ENHANCED - Analytics Dashboard

setSelectedTimeRange(value as any)} className="w-auto"> 7 Days 30 Days 90 Days All Time
{/* Overview Cards */}
Total Memories 🧠
{stats.total}

Across {Object.keys(stats.projects).length} projects

Recent Activity
{stats.recentActivity.thisWeek}

This week ({stats.recentActivity.today} today)

Average Size 📏
{stats.averageSize}

characters per memory

Active Project 🎯
{stats.mostActiveProject?.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()) || 'General'}

{stats.projects[stats.mostActiveProject || 'general'] || 0} memories

{/* Categories and Projects */}
{/* Categories Breakdown */} 📂 Categories {Object.entries(stats.categories) .sort(([,a], [,b]) => b - a) .map(([category, count]) => { const percentage = Math.round((count / stats.total) * 100) return (
{getCategoryIcon(category)} {category.replace(/-/g, ' ')}
{count}
) })}
{/* Projects Breakdown */} 📁 Projects {Object.entries(stats.projects) .sort(([,a], [,b]) => b - a) .slice(0, 8) .map(([project, count]) => { const percentage = Math.round((count / stats.total) * 100) return (
📁 {project.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}
{count}
) })}
{/* Complexity Levels and Content Types */}
{/* Complexity Levels */} 🎯 Complexity Levels {Object.entries(stats.complexityLevels) .sort(([a], [b]) => Number(a) - Number(b)) .map(([level, count]) => { const percentage = stats.total > 0 ? Math.round((count / stats.total) * 100) : 0 const labels = ['Simple', 'Enhanced', 'Project', 'Advanced'] return (
{getComplexityIcon(Number(level))} Level {level}: {labels[Number(level) - 1]}
{count}
) })}
{/* Content Types */} 📄 Content Types {Object.entries(stats.contentTypes) .sort(([,a], [,b]) => b - a) .map(([type, count]) => { const percentage = Math.round((count / stats.total) * 100) const icons: Record = { text: '📝', code: '💻', structured: '🗂️' } return (
{icons[type] || '📄'} {type}
{count}
) })}
{/* Trending Tags */} 🏷️ Trending Tags {stats.trendingTags.length > 0 ? (
{stats.trendingTags.map((tag, index) => ( #{tag} ({stats.tags[tag]}) ))}
) : (

No tags found in selected time range

)}
{/* Insights */} {stats.largestMemory && ( 💡 Insights
📝

Largest Memory

{stats.largestMemory.content.substring(0, 100)}...

{stats.largestMemory.content.length} characters • {formatDistanceToNow(stats.largestMemory.timestamp)}

📈
Growth Rate
{stats.memoryGrowth.length > 1 ? `${Math.round((stats.recentActivity.thisWeek / 7) * 10) / 10} memories/day` : 'Not enough data' }
🎯
Tag Diversity
{Object.keys(stats.tags).length} unique tags
)}
) }