Untitled
unknown
plain_text
10 months ago
8.5 kB
7
Indexable
"use client"
import { useState, useMemo } from "react"
import { format } from "date-fns"
import { CalendarIcon } from "lucide-react"
import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts"
import { useMetrics } from "@/hooks/useMetrics"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
const fillLevelRanges = [
{ label: "0-20%", min: 0, max: 20 },
{ label: "21-40%", min: 21, max: 40 },
{ label: "41-60%", min: 41, max: 60 },
{ label: "61-80%", min: 61, max: 80 },
{ label: "81-100%", min: 81, max: 100 },
]
const periods = [
{ label: "All Time", value: "all" },
{ label: "Last 24h", value: "24h" },
{ label: "Last Week", value: "week" },
{ label: "Last Month", value: "month" },
{ label: "Last Year", value: "year" },
{ label: "Custom", value: "custom" },
]
export function ProactiveEmptyingChart() {
const { metrics, helpers } = useMetrics()
const [selectedPeriod, setSelectedPeriod] = useState("all")
const [selectedBin, setSelectedBin] = useState("all")
const [selectedType, setSelectedType] = useState("all")
const [customDateRange, setCustomDateRange] = useState<{ from: Date | undefined; to: Date | undefined }>({
from: undefined,
to: undefined,
})
const chartData = useMemo(() => {
if (!metrics || !helpers) return []
const now = new Date()
let timeFilter
if (selectedPeriod === "all") {
timeFilter = undefined
} else if (selectedPeriod === "custom") {
timeFilter = customDateRange.from && customDateRange.to
? { start: customDateRange.from, end: customDateRange.to }
: undefined
} else {
let startDate = new Date(now)
switch (selectedPeriod) {
case "24h":
startDate = new Date(now.getTime() - 24 * 60 * 60 * 1000)
break
case "week":
startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000)
break
case "month":
startDate = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate())
break
case "year":
startDate = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate())
break
}
timeFilter = { start: startDate, end: now }
}
const events = helpers.getEmptyingEvents(
selectedBin === "all" ? undefined : selectedBin,
timeFilter
)
const rangeCounts = fillLevelRanges.map(range => ({
range: range.label,
proactive: 0,
normal: 0,
}))
events.forEach(event => {
const range = fillLevelRanges.find(r =>
event.fill_level > r.min && event.fill_level <= r.max
)
if (!range) return
const idx = fillLevelRanges.indexOf(range)
const isProactive = event.fill_level < 90
if (selectedType === "proactive" && isProactive) {
rangeCounts[idx].proactive++
} else if (selectedType === "normal" && !isProactive) {
rangeCounts[idx].normal++
} else {
isProactive ? rangeCounts[idx].proactive++ : rangeCounts[idx].normal++
}
})
return rangeCounts.map(item => ({
...item,
total: item.proactive + item.normal,
}))
}, [metrics, selectedPeriod, selectedBin, selectedType, helpers, customDateRange])
const activeBins = helpers?.getActiveBinIds() || []
const chartConfig = {
...(selectedType !== "normal" && { proactive: {
label: "Proactive",
color: "hsl(var(--chart-1))"
}}),
...(selectedType !== "proactive" && { normal: {
label: "Normal",
color: "hsl(var(--chart-2))"
}}),
} satisfies ChartConfig
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between gap-4">
<div>
<CardTitle>Emptying Statistics</CardTitle>
<CardDescription>Distribution of emptying events by fill level</CardDescription>
</div>
<div className="flex gap-2">
<Select value={selectedPeriod} onValueChange={setSelectedPeriod}>
<SelectTrigger className="w-[120px]">
<SelectValue placeholder="Period" />
</SelectTrigger>
<SelectContent>
{periods.map((period) => (
<SelectItem key={period.value} value={period.value}>
{period.label}
</SelectItem>
))}
</SelectContent>
</Select>
<Select value={selectedBin} onValueChange={setSelectedBin}>
<SelectTrigger className="w-[100px]">
<SelectValue placeholder="Bin" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All</SelectItem>
{activeBins.map(bin => (
<SelectItem key={bin} value={bin}>{bin}</SelectItem>
))}
</SelectContent>
</Select>
<Select value={selectedType} onValueChange={setSelectedType}>
<SelectTrigger className="w-[120px]">
<SelectValue placeholder="Type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All</SelectItem>
<SelectItem value="proactive">Proactive</SelectItem>
<SelectItem value="normal">Normal</SelectItem>
</SelectContent>
</Select>
{selectedPeriod === "custom" && (
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" className="w-[280px] justify-start text-left font-normal">
<CalendarIcon className="mr-2 h-4 w-4" />
{customDateRange.from ? (
customDateRange.to ? (
<>
{format(customDateRange.from, "LLL dd, y")} - {format(customDateRange.to, "LLL dd, y")}
</>
) : (
format(customDateRange.from, "LLL dd, y")
)
) : (
<span>Pick a date range</span>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
initialFocus
mode="range"
defaultMonth={customDateRange.from}
selected={customDateRange}
onSelect={setCustomDateRange}
numberOfMonths={2}
/>
</PopoverContent>
</Popover>
)}
</div>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="aspect-auto h-[400px] w-full">
<BarChart data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="range"
tickLine={false}
axisLine={false}
tickMargin={10}
/>
<YAxis
tickLine={false}
axisLine={false}
tickFormatter={(value) => `${value}`}
/>
<ChartTooltip content={<ChartTooltipContent />} />
{selectedType !== "normal" && (
<Bar
dataKey="proactive"
fill="var(--color-proactive)"
radius={4}
stackId="a"
/>
)}
{selectedType !== "proactive" && (
<Bar
dataKey="normal"
fill="var(--color-normal)"
radius={4}
stackId="a"
/>
)}
</BarChart>
</ChartContainer>
</CardContent>
<CardFooter className="text-sm text-muted-foreground">
Proactive emptying = below 90% fill level | Normal emptying = 90%+
</CardFooter>
</Card>
)
}Editor is loading...
Leave a Comment