proj/Frontend/components/tickets/ticket-table.tsx
2026-01-21 09:52:33 +01:00

143 lines
5.3 KiB
TypeScript

"use client"
import { useState, useMemo } from "react"
import type { Ticket, TicketStatus } from "@/lib/types"
import { StatusBadge } from "./status-badge"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { ArrowUpDown, ArrowDown, ArrowUp, Calendar, MapPin, FileText } from "lucide-react"
import { Button } from "@/components/ui/button"
interface TicketTableProps {
tickets: Ticket[]
showStatusUpdate?: boolean
onStatusUpdate?: (ticketId: number, status: TicketStatus) => void
}
type SortDirection = "asc" | "desc"
export function TicketTable({ tickets, showStatusUpdate = false, onStatusUpdate }: TicketTableProps) {
const [sortDirection, setSortDirection] = useState<SortDirection>("desc")
const sortedTickets = useMemo(() => {
return [...tickets].sort((a, b) => {
const dateA = new Date(a.createdAt).getTime()
const dateB = new Date(b.createdAt).getTime()
return sortDirection === "desc" ? dateB - dateA : dateA - dateB
})
}, [tickets, sortDirection])
const toggleSort = () => {
setSortDirection((prev) => (prev === "desc" ? "asc" : "desc"))
}
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString("de-DE", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit"
})
}
if (tickets.length === 0) {
return (
<div className="flex flex-col items-center justify-center rounded-lg border border-dashed border-border p-12 text-center">
<FileText className="h-12 w-12 text-muted-foreground/50" />
<h3 className="mt-4 text-lg font-medium">No tickets found</h3>
<p className="mt-2 text-sm text-muted-foreground">
There are no tickets to display at this time.
</p>
</div>
)
}
return (
<div className="rounded-lg border border-border bg-card overflow-hidden">
<Table>
<TableHeader>
<TableRow className="bg-muted/50 hover:bg-muted/50">
<TableHead className="font-semibold">
<div className="flex items-center gap-2">
<MapPin className="h-4 w-4" />
Room
</div>
</TableHead>
<TableHead className="font-semibold">Title</TableHead>
<TableHead className="font-semibold hidden md:table-cell">Description</TableHead>
<TableHead className="font-semibold">
<Button
variant="ghost"
size="sm"
onClick={toggleSort}
className="flex items-center gap-1 -ml-2 h-auto p-2 hover:bg-transparent"
>
<Calendar className="h-4 w-4" />
Date
{sortDirection === "desc" ? (
<ArrowDown className="h-3 w-3" />
) : (
<ArrowUp className="h-3 w-3" />
)}
</Button>
</TableHead>
<TableHead className="font-semibold">Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{sortedTickets.map((ticket) => (
<TableRow key={ticket.id} className="group">
<TableCell className="font-medium">{ticket.room.name}</TableCell>
<TableCell className="font-medium">{ticket.title}</TableCell>
<TableCell className="hidden md:table-cell max-w-xs">
<p className="truncate text-muted-foreground">{ticket.description}</p>
</TableCell>
<TableCell className="text-muted-foreground">{formatDate(ticket.createdAt)}</TableCell>
<TableCell>
{showStatusUpdate && onStatusUpdate ? (
<Select
value={ticket.status}
onValueChange={(value: TicketStatus) => onStatusUpdate(ticket.id, value)}
>
<SelectTrigger className="w-32 h-8">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="OPEN">
<div className="flex items-center gap-2">
<span className="h-2 w-2 rounded-full bg-status-open" />
Offen
</div>
</SelectItem>
<SelectItem value="IN_PROGRESS">
<div className="flex items-center gap-2">
<span className="h-2 w-2 rounded-full bg-status-progress" />
In Bearbeitung
</div>
</SelectItem>
<SelectItem value="CLOSED">
<div className="flex items-center gap-2">
<span className="h-2 w-2 rounded-full bg-status-done" />
Erledigt
</div>
</SelectItem>
</SelectContent>
</Select>
) : (
<StatusBadge status={ticket.status} />
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)
}