Untitled
unknown
plain_text
a year ago
12 kB
6
Indexable
"use client"
import * as React from "react"
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts"
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from "@/components/ui/card"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import {
ChartConfig,
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart"
const chartConfig = {
bin1: {
label: "Bio",
color: "hsl(var(--chart-1))",
},
bin2: {
label: "Recycling",
color: "hsl(var(--chart-2))",
},
bin3: {
label: "Paper",
color: "hsl(var(--chart-3))",
},
bin4: {
label: "Residual",
color: "hsl(var(--chart-4))",
},
} satisfies ChartConfig
export function FillRates({ currentFillLevels }) {
const [timeRange, setTimeRange] = React.useState("90d")
// For now, let's create demo data based on current fill levels
const generateHistoricalData = () => {
const data = []
const endDate = new Date()
const startDate = new Date()
startDate.setDate(endDate.getDate() - 90) // 90 days ago
for (let date = new Date(startDate); date <= endDate; date.setDate(date.getDate() + 1)) {
// Create random variations of current fill levels
data.push({
date: date.toISOString().split('T')[0],
bin1: Math.max(0, Math.min(100, currentFillLevels.bin1 + (Math.random() - 0.5) * 20)),
bin2: Math.max(0, Math.min(100, currentFillLevels.bin2 + (Math.random() - 0.5) * 20)),
bin3: Math.max(0, Math.min(100, currentFillLevels.bin3 + (Math.random() - 0.5) * 20)),
bin4: Math.max(0, Math.min(100, currentFillLevels.bin4 + (Math.random() - 0.5) * 20)),
})
}
return data
}
const chartData = generateHistoricalData()
// Filter data based on selected time range
const filteredData = chartData.filter((item) => {
const date = new Date(item.date)
const referenceDate = new Date()
let daysToSubtract = 90
if (timeRange === "30d") daysToSubtract = 30
if (timeRange === "7d") daysToSubtract = 7
const startDate = new Date(referenceDate)
startDate.setDate(startDate.getDate() - daysToSubtract)
return date >= startDate
})
return (
<Card>
<CardHeader className="flex items-center gap-2 space-y-0 border-b py-4 sm:flex-row">
<div className="grid flex-1 gap-1 text-center sm:text-left">
<CardTitle>Fill Levels Over Time</CardTitle>
<CardDescription>Historical fill levels for all bins</CardDescription>
</div>
<Select value={timeRange} onValueChange={setTimeRange}>
<SelectTrigger className="w-[160px] rounded-lg">
<SelectValue placeholder="Last 3 months" />
</SelectTrigger>
<SelectContent>
<SelectItem value="90d">Last 3 months</SelectItem>
<SelectItem value="30d">Last 30 days</SelectItem>
<SelectItem value="7d">Last 7 days</SelectItem>
</SelectContent>
</Select>
</CardHeader>
<CardContent className="pt-4">
<ChartContainer config={chartConfig} className="h-[300px]">
<AreaChart data={filteredData}>
<defs>
{Object.keys(chartConfig).map((bin) => (
<linearGradient
key={bin}
id={`fill${bin}`}
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="5%"
stopColor={`var(--color-${bin})`}
stopOpacity={0.8}
/>
<stop
offset="95%"
stopColor={`var(--color-${bin})`}
stopOpacity={0.1}
/>
</linearGradient>
))}
</defs>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="date"
tickLine={false}
axisLine={false}
tickMargin={8}
minTickGap={32}
tickFormatter={(value) => {
const date = new Date(value)
return date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
})
}}
/>
<YAxis
tickLine={false}
axisLine={false}
tickMargin={8}
domain={[0, 100]}
tickFormatter={(value) => `${value}%`}
/>
<ChartTooltip
content={
<ChartTooltipContent
labelFormatter={(value) => {
return new Date(value).toLocaleDateString("en-US", {
month: "long",
day: "numeric",
year: "numeric",
})
}}
/>
}
/>
{Object.keys(chartConfig).map((bin) => (
<Area
key={bin}
dataKey={bin}
type="monotone"
fill={`url(#fill${bin})`}
stroke={`var(--color-${bin})`}
strokeWidth={2}
/>
))}
<ChartLegend content={<ChartLegendContent />} />
</AreaChart>
</ChartContainer>
</CardContent>
</Card>
)
}
"use client"
import { useEffect, useState } from "react"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Overview } from "@/components/statistics/overview"
import { DailySorting } from "@/components/statistics/daily-sorting"
import { HourlyActivity } from "@/components/statistics/hourly-activity"
import { FillRates } from "@/components/statistics/fill-rates"
import { ModelUsage } from "@/components/statistics/model-usage"
import { ClassificationTimes } from "@/components/statistics/classification-times"
import { Activity, Brain, ChartBar, LineChart, Recycle, Timer } from "lucide-react"
export default function StatisticsPage() {
const [isLoading, setIsLoading] = useState(true)
const [data, setData] = useState(null)
const [fillLevels, setFillLevels] = useState(null)
useEffect(() => {
// Fetch both stats and fill levels
Promise.all([
fetch('/api/stats').then(res => res.json()),
fetch('/api/fill-levels').then(res => res.json())
])
.then(([statsData, fillLevelsData]) => {
setData(statsData)
setFillLevels(fillLevelsData)
setIsLoading(false)
})
.catch(error => {
console.error('Error fetching data:', error)
setIsLoading(false)
})
}, [])
if (isLoading) {
return <div className="flex items-center justify-center h-screen">Loading...</div>
}
return (
<div className="flex-1 space-y-4 p-8 pt-6">
<div className="flex items-center justify-between space-y-2">
<h2 className="text-3xl font-bold tracking-tight">Statistics</h2>
</div>
{/* Quick Stats Cards */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Items</CardTitle>
<Recycle className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{data?.summary?.total_sorts || 0}</div>
<p className="text-xs text-muted-foreground">
+{data?.summary?.today_sorts || 0} today
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">API Usage</CardTitle>
<Activity className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{Math.round((data?.summary?.model_usage_total?.api /
(data?.summary?.model_usage_total?.api +
data?.summary?.model_usage_total?.local || 1)) * 100)}%
</div>
<p className="text-xs text-muted-foreground">Of total classifications</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Response Time</CardTitle>
<Timer className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{data?.summary?.avg_classification_time_ms || 0}ms
</div>
<p className="text-xs text-muted-foreground">Average classification speed</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Daily Average</CardTitle>
<ChartBar className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{Math.round(data?.summary?.total_sorts /
(Object.keys(data?.daily_stats || {}).length || 1))}
</div>
<p className="text-xs text-muted-foreground">Items per day</p>
</CardContent>
</Card>
</div>
{/* Main Content Tabs */}
<Tabs defaultValue="overview" className="space-y-4">
<TabsList>
<TabsTrigger value="overview" className="gap-2">
<LineChart className="h-4 w-4" />
Overview
</TabsTrigger>
<TabsTrigger value="sorting" className="gap-2">
<ChartBar className="h-4 w-4" />
Sorting
</TabsTrigger>
<TabsTrigger value="bins" className="gap-2">
<Recycle className="h-4 w-4" />
Bins
</TabsTrigger>
<TabsTrigger value="performance" className="gap-2">
<Activity className="h-4 w-4" />
Performance
</TabsTrigger>
</TabsList>
<TabsContent value="overview" className="space-y-4">
<Overview data={data} />
</TabsContent>
<TabsContent value="sorting" className="space-y-4">
<div className="grid gap-4 md:grid-cols-2">
<DailySorting data={data} />
<HourlyActivity data={data} />
</div>
</TabsContent>
<TabsContent value="bins" className="space-y-4">
<FillRates currentFillLevels={fillLevels} />
</TabsContent>
<TabsContent value="performance" className="space-y-4">
<div className="grid gap-4 md:grid-cols-2">
<ModelUsage data={data} />
<ClassificationTimes data={data} />
</div>
</TabsContent>
</Tabs>
</div>
)
}Editor is loading...
Leave a Comment