140 lines
5.9 KiB
TypeScript
140 lines
5.9 KiB
TypeScript
"use client"
|
|
|
|
import { useMemo } from "react"
|
|
import { useAuth } from "@/lib/auth-context"
|
|
import { TicketTable } from "@/components/tickets/ticket-table"
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Badge } from "@/components/ui/badge"
|
|
import { Building2, Ticket, Clock, CheckCircle2, AlertCircle } from "lucide-react"
|
|
|
|
export function SupervisorDashboard() {
|
|
const { user, tickets, updateTicketStatus } = useAuth()
|
|
|
|
const supervisedRooms = user?.supervisedRooms || []
|
|
|
|
const roomTickets = useMemo(() => {
|
|
if (!supervisedRooms.length) return []
|
|
const roomIds = supervisedRooms.map(r => r.id)
|
|
return tickets.filter((t) => roomIds.includes(t.room.id))
|
|
}, [tickets, supervisedRooms])
|
|
|
|
const stats = useMemo(() => {
|
|
const open = roomTickets.filter((t) => t.status === "OPEN").length
|
|
const inProgress = roomTickets.filter((t) => t.status === "IN_PROGRESS").length
|
|
const done = roomTickets.filter((t) => t.status === "CLOSED").length
|
|
return { open, inProgress, done, total: roomTickets.length }
|
|
}, [roomTickets])
|
|
|
|
const roomStats = useMemo(() => {
|
|
return supervisedRooms.map((room) => {
|
|
const roomTicketsList = roomTickets.filter((t) => t.room.id === room.id)
|
|
return {
|
|
room: room.name,
|
|
total: roomTicketsList.length,
|
|
open: roomTicketsList.filter((t) => t.status === "OPEN").length,
|
|
inProgress: roomTicketsList.filter((t) => t.status === "IN_PROGRESS").length,
|
|
done: roomTicketsList.filter((t) => t.status === "CLOSED").length,
|
|
}
|
|
})
|
|
}, [supervisedRooms, roomTickets])
|
|
|
|
return (
|
|
<div className="space-y-8">
|
|
<div>
|
|
<h1 className="text-2xl font-semibold tracking-tight">Raumbetreuer-Dashboard</h1>
|
|
<p className="text-muted-foreground mt-1">Verwalten Sie Tickets für Ihre Räume</p>
|
|
</div>
|
|
|
|
<div className="grid gap-4 md:grid-cols-4">
|
|
<Card className="border-border/60">
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
<CardTitle className="text-sm font-medium text-muted-foreground">Gesamt Tickets</CardTitle>
|
|
<Ticket className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{stats.total}</div>
|
|
</CardContent>
|
|
</Card>
|
|
<Card className="border-border/60">
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
<CardTitle className="text-sm font-medium text-muted-foreground">Offen</CardTitle>
|
|
<AlertCircle className="h-4 w-4 text-status-open-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold text-status-open-foreground">{stats.open}</div>
|
|
</CardContent>
|
|
</Card>
|
|
<Card className="border-border/60">
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
<CardTitle className="text-sm font-medium text-muted-foreground">In Bearbeitung</CardTitle>
|
|
<Clock className="h-4 w-4 text-status-progress-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold text-status-progress-foreground">{stats.inProgress}</div>
|
|
</CardContent>
|
|
</Card>
|
|
<Card className="border-border/60">
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
<CardTitle className="text-sm font-medium text-muted-foreground">Erledigt</CardTitle>
|
|
<CheckCircle2 className="h-4 w-4 text-status-done-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold text-status-done-foreground">{stats.done}</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<Card className="border-border/60">
|
|
<CardHeader>
|
|
<div className="flex items-center gap-2">
|
|
<Building2 className="h-5 w-5 text-primary" />
|
|
<CardTitle className="text-xl">Raumübersicht</CardTitle>
|
|
</div>
|
|
<CardDescription>Status der Tickets pro Raum</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
|
|
{roomStats.map((stat) => (
|
|
<div
|
|
key={stat.room}
|
|
className="rounded-lg border border-border bg-muted/30 p-4 transition-colors hover:bg-muted/50"
|
|
>
|
|
<h3 className="font-medium">{stat.room}</h3>
|
|
<div className="mt-2 flex flex-wrap gap-2">
|
|
{stat.open > 0 && (
|
|
<Badge variant="secondary" className="bg-status-open/20 text-status-open-foreground">
|
|
{stat.open} Offen
|
|
</Badge>
|
|
)}
|
|
{stat.inProgress > 0 && (
|
|
<Badge variant="secondary" className="bg-status-progress/20 text-status-progress-foreground">
|
|
{stat.inProgress} In Bearb.
|
|
</Badge>
|
|
)}
|
|
{stat.done > 0 && (
|
|
<Badge variant="secondary" className="bg-status-done/20 text-status-done-foreground">
|
|
{stat.done} Fertig
|
|
</Badge>
|
|
)}
|
|
{stat.total === 0 && (
|
|
<span className="text-sm text-muted-foreground">Keine Tickets</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="border-border/60">
|
|
<CardHeader>
|
|
<CardTitle className="text-xl">Alle Raum-Tickets</CardTitle>
|
|
<CardDescription>Verwalten Sie den Status der Tickets</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<TicketTable tickets={roomTickets} showStatusUpdate onStatusUpdate={updateTicketStatus} />
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)
|
|
}
|