taskmanager/src/components/tasks/task-info-card.tsx
2025-11-12 17:16:01 +01:00

209 lines
5.5 KiB
TypeScript

import { format, isPast } from "date-fns";
import { de } from "date-fns/locale";
import { Calendar, MapPin, User } from "lucide-react";
import {
Card,
CardContent,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Separator } from "@/components/ui/separator";
import { Label } from "@/components/ui/label";
import { TaskStatus, TaskWithRelations } from "@/types";
import { Badge } from "../ui/badge";
/**
* Props für TaskInfoCard Component
*/
interface TaskInfoCardProps {
task: TaskWithRelations;
}
/**
* Task Info Card Component
* Zeigt alle Details einer Task an
* - Nur shadcn/ui Komponenten (Card, Avatar, Separator, Label)
* - Formatierung mit date-fns
*/
export function TaskInfoCard({ task }: TaskInfoCardProps) {
/**
* Badge Name basierend auf Status
*/
const getStatusName = (status: TaskStatus) => {
switch (status) {
case "UNERLEDIGT":
return "Unerledigt" as const;
case "IN_BEARBEITUNG":
return "In Bearbeitung" as const;
case "ERLEDIGT":
return "Erledigt" as const;
default:
return "Unerledigt" as const;
}
};
/**
* Badge Variant basierend auf Status
*/
const getStatusVariant = (status: TaskStatus) => {
switch (status) {
case "UNERLEDIGT":
return "destructive" as const;
case "IN_BEARBEITUNG":
return "secondary" as const;
case "ERLEDIGT":
return "default" as const;
default:
return "outline" as const;
}
};
/**
* Initialen für Avatar generieren
*/
const getInitials = (name: string) => {
return name
.split(" ")
.map((n) => n[0])
.join("")
.toUpperCase()
.slice(0, 2);
};
/**
* Prüfe ob Frist überschritten ist
*/
const isOverdue = isPast(new Date(task.bisWann)) && task.status !== "ERLEDIGT";
return (
<Card>
<CardHeader>
<CardTitle>Details</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{/* Status */}
<div className="space-y-2">
<Label className="flex items-center gap-2">
<Calendar className="h-4 w-4" />
Status
</Label>
<div>
<Badge variant={getStatusVariant(task.status)}>
{getStatusName(task.status)}
</Badge>
</div>
</div>
<Separator />
{/* Ort */}
<div className="space-y-2">
<Label className="flex items-center gap-2">
<MapPin className="h-4 w-4" />
Ort
</Label>
<p className="text-sm">{task.wo}</p>
</div>
<Separator />
{/* Frist */}
<div className="space-y-2">
<Label className="flex items-center gap-2">
<Calendar className="h-4 w-4" />
Frist
</Label>
<p className={`text-sm ${isOverdue ? "text-destructive font-semibold" : ""}`}>
{format(new Date(task.bisWann), "dd.MM.yyyy", { locale: de })}
{isOverdue && " (überfällig)"}
</p>
</div>
<Separator />
{/* Zuständig */}
{task.assignee && (
<>
<div className="space-y-2">
<Label className="flex items-center gap-2">
<User className="h-4 w-4" />
Zuständig
</Label>
<div className="flex items-center gap-2">
<Avatar>
<AvatarFallback>
{getInitials(task.assignee.name)}
</AvatarFallback>
</Avatar>
<div>
<p className="text-sm font-medium">{task.assignee.name}</p>
<p className="text-xs text-muted-foreground">
{task.assignee.email}
</p>
</div>
</div>
</div>
<Separator />
</>
)}
{/* Erstellt von */}
<div className="space-y-2">
<Label>Erstellt von</Label>
<div className="flex items-center gap-2">
<Avatar>
<AvatarFallback>
{getInitials(task.creator.name)}
</AvatarFallback>
</Avatar>
<div>
<p className="text-sm font-medium">{task.creator.name}</p>
<p className="text-xs text-muted-foreground">
{task.creator.email}
</p>
</div>
</div>
</div>
<Separator />
{/* Erstellt am */}
<div className="space-y-2">
<Label>Erstellt am</Label>
<p className="text-sm">
{format(new Date(task.createdAt), "dd.MM.yyyy HH:mm", { locale: de })}
</p>
</div>
{/* Optional: Beauftragt am */}
{task.beauftragtAm && (
<>
<Separator />
<div className="space-y-2">
<Label>Beauftragt am</Label>
<p className="text-sm">
{format(new Date(task.beauftragtAm), "dd.MM.yyyy", { locale: de })}
</p>
</div>
</>
)}
{/* Optional: Firma beauftragt */}
{task.firmaBeauftragt && (
<>
<Separator />
<div className="space-y-2">
<Label>Firma beauftragt</Label>
<p className="text-sm">{task.firmaBeauftragt}</p>
</div>
</>
)}
</CardContent>
</Card>
);
}