Add non-destructive dev seed on startup
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
"use client";
|
||||
|
||||
import { useTransition } from "react";
|
||||
import { format } from "date-fns";
|
||||
import { de } from "date-fns/locale";
|
||||
import { Check, X, Clock, CalendarIcon } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { Termin, User } from "@prisma/client";
|
||||
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { approveTermin, rejectTermin } from "../actions";
|
||||
|
||||
type PendingTermin = Termin & {
|
||||
createdBy: { firstName: string; lastName: string } | null;
|
||||
};
|
||||
|
||||
export function PendingAnfragen({ termine }: { termine: PendingTermin[] }) {
|
||||
if (termine.length === 0) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center rounded-lg border border-dashed p-8 text-center animate-in fade-in-50">
|
||||
<CalendarIcon className="h-10 w-10 text-muted-foreground mb-4" />
|
||||
<h3 className="text-lg font-semibold">Keine ausstehenden Anfragen</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Es gibt aktuell keine Terminanfragen, die bestätigt werden müssen.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
{termine.map((termin) => (
|
||||
<PendingTerminCard key={termin.id} termin={termin} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function PendingTerminCard({ termin }: { termin: PendingTermin }) {
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
const handleApprove = () => {
|
||||
startTransition(async () => {
|
||||
const res = await approveTermin(termin.id);
|
||||
if (res.error) {
|
||||
toast.error(res.error);
|
||||
} else {
|
||||
toast.success("Anfrage freigegeben.");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleReject = () => {
|
||||
// In a real app, you might want to ask for a rejection reason in a prompt/modal.
|
||||
startTransition(async () => {
|
||||
const res = await rejectTermin(termin.id);
|
||||
if (res.error) {
|
||||
toast.error(res.error);
|
||||
} else {
|
||||
toast.success("Anfrage abgelehnt.");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="flex items-center justify-between p-4 sm:p-6">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="font-semibold">{termin.title}</div>
|
||||
<div className="text-sm text-muted-foreground flex items-center gap-1">
|
||||
<Clock className="h-3.5 w-3.5" />
|
||||
{format(termin.startDate, "PP", { locale: de })}
|
||||
{!termin.allDay && ` • ${format(termin.startDate, "p", { locale: de })}`}
|
||||
</div>
|
||||
<div className="text-sm font-medium text-primary mt-1">
|
||||
Angefragt von: {termin.createdBy?.firstName} {termin.createdBy?.lastName}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="text-destructive hover:bg-destructive hover:text-destructive-foreground border-destructive/20"
|
||||
onClick={handleReject}
|
||||
disabled={isPending}
|
||||
>
|
||||
<X className="h-4 w-4 sm:mr-2" />
|
||||
<span className="hidden sm:inline">Ablehnen</span>
|
||||
</Button>
|
||||
<Button
|
||||
className="bg-emerald-600 hover:bg-emerald-700 text-white"
|
||||
onClick={handleApprove}
|
||||
disabled={isPending}
|
||||
>
|
||||
<Check className="h-4 w-4 sm:mr-2" />
|
||||
<span className="hidden sm:inline">Freigeben</span>
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user