Untitled

 avatar
unknown
plain_text
5 days ago
5.6 kB
1
Indexable
// components/overview-cards.tsx
"use client"

import { useMetrics } from "@/hooks/useMetrics"
import { useBinConfig } from "@/hooks/use-bin-config"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Gauge, Clock, Trash2, TrendingUp } from "lucide-react"
import { Badge } from "@/components/ui/badge"
import { format, differenceInHours, differenceInDays, subDays } from "date-fns"

export function OverviewCards() {
  const { metrics } = useMetrics()
  const { bins } = useBinConfig()

  // Card 1: Proactive emptying count
  const proactiveEmptyings = metrics?.proactive_emptying?.count || 0
  const totalEmptyings = metrics?.basic_metrics?.bin_emptying_counts 
    ? Object.values(metrics.basic_metrics.bin_emptying_counts).reduce((a, b) => a + b, 0)
    : 0
  const proactivePercentage = totalEmptyings > 0 
    ? Math.round((proactiveEmptyings / totalEmptyings) * 100)
    : 0

  // Card 2: Next full bin prediction
  const predictions = metrics?.fill_predictions || {}
  const nextFullBin = Object.entries(predictions).reduce((acc, [binId, prediction]) => {
    const predictedTime = new Date(prediction.predicted_full_time)
    return (!acc || predictedTime < acc.predictedTime) ? { 
      binId,
      predictedTime,
      currentLevel: prediction.current_level,
      binName: bins.find(b => b.id === binId)?.name || `Mülleimer ${binId.slice(-1)}`
    } : acc
  }, null as { 
    binId: string
    binName: string
    predictedTime: Date
    currentLevel: number
  } | null)

  // Card 3: Average fill level at emptying
  const fillLevels = metrics?.fill_level_history 
    ? Object.values(metrics.fill_level_history).flatMap(h => h.fill_levels_at_empty)
    : []
  const averageFillLevel = fillLevels.length > 0
    ? Math.round(fillLevels.reduce((a, b) => a + b, 0) / fillLevels.length)
    : null

  // Card 4: Total emptyings count with weekly calculation
  const totalEmptyingsLastWeek = metrics?.fill_level_history 
    ? Object.values(metrics.fill_level_history).reduce((total, binHistory) => {
        const lastWeek = subDays(new Date(), 7)
        return binHistory.emptying_timestamps.filter(t => 
          new Date(t) > lastWeek
        ).length + total
      }, 0)
    : 0

  // Format time remaining display
  const formatTimeRemaining = (endDate: Date) => {
    const hours = differenceInHours(endDate, new Date())
    if (hours >= 24) {
      const days = (hours / 24).toFixed(1)
      return `${days} Tage verbleibend`
    }
    return `${hours} Stunden verbleibend`
  }

  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
      {/* Proactive Emptying Card */}
      <Card>
        <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle className="text-sm font-medium">Proaktive Leerungen</CardTitle>
          <Trash2 className="h-4 w-4 text-muted-foreground" />
        </CardHeader>
        <CardContent>
          <div className="text-2xl font-bold">{proactiveEmptyings}</div>
          <p className="text-xs text-muted-foreground">
            {totalEmptyings} Gesamtleerungen ({proactivePercentage}%)
          </p>
        </CardContent>
      </Card>

      {/* Next Full Bin Card */}
      <Card>
        <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle className="text-sm font-medium">Nächste volle Tonne</CardTitle>
          <Clock className="h-4 w-4 text-muted-foreground" />
        </CardHeader>
        <CardContent>
          {nextFullBin ? (
            <>
              <div className="text-2xl font-bold mb-1">
                {nextFullBin.binName}
              </div>
              <div className="text-xs text-muted-foreground">
                Aktuell: {Math.round(nextFullBin.currentLevel)}% voll
              </div>
              <div className="text-xs text-muted-foreground">
                {format(nextFullBin.predictedTime, "dd.MM.yyyy HH:mm")}
              </div>
              <div className="text-xs text-muted-foreground mt-1">
                {formatTimeRemaining(nextFullBin.predictedTime)}
              </div>
            </>
          ) : (
            <div className="text-sm text-muted-foreground">Keine Vorhersagen</div>
          )}
        </CardContent>
      </Card>

      {/* Average Fill Level Card */}
      <Card>
        <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle className="text-sm font-medium">Durchschn. Füllstand</CardTitle>
          <Gauge className="h-4 w-4 text-muted-foreground" />
        </CardHeader>
        <CardContent>
          <div className="text-2xl font-bold">
            {averageFillLevel !== null ? `${averageFillLevel}%` : "N/A"}
          </div>
          <p className="text-xs text-muted-foreground">
            Bei Leerungen
          </p>
        </CardContent>
      </Card>

      {/* Total Emptyings Card */}
      <Card>
        <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle className="text-sm font-medium">Leerungen gesamt</CardTitle>
          <Trash2 className="h-4 w-4 text-muted-foreground" />
        </CardHeader>
        <CardContent>
          <div className="text-2xl font-bold">{totalEmptyings}</div>
          <p className="text-xs text-muted-foreground">
            +{totalEmptyingsLastWeek} letzte Woche
          </p>
        </CardContent>
      </Card>
    </div>
  )
}
Leave a Comment