Add non-destructive dev seed on startup
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
"use client";
|
||||
|
||||
import { Termin, MitbringselItem, TerminType, TerminStatus } from "@prisma/client";
|
||||
import { format } from "date-fns";
|
||||
import { de } from "date-fns/locale";
|
||||
import { Calendar, Clock, MapPin, AlignLeft } from "lucide-react";
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { MitbringselList } from "./mitbringsel-list";
|
||||
import { toggleMitbringselList } from "../actions";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useTransition } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
type TerminWithItems = Termin & {
|
||||
mitbringselItems?: (MitbringselItem & {
|
||||
user: { firstName: string; lastName: string };
|
||||
})[];
|
||||
};
|
||||
|
||||
export function TerminList({
|
||||
termine,
|
||||
userId,
|
||||
isAdmin,
|
||||
}: {
|
||||
termine: TerminWithItems[];
|
||||
userId: string;
|
||||
isAdmin: boolean;
|
||||
}) {
|
||||
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">
|
||||
<div className="mx-auto flex max-w-[420px] flex-col items-center justify-center text-center">
|
||||
<Calendar className="h-10 w-10 text-muted-foreground mb-4" />
|
||||
<h3 className="mt-4 text-lg font-semibold">Keine Termine</h3>
|
||||
<p className="mb-4 mt-2 text-sm text-muted-foreground">
|
||||
Es stehen aktuell keine Termine an.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{termine.map((termin) => (
|
||||
<TerminCard
|
||||
key={termin.id}
|
||||
termin={termin}
|
||||
userId={userId}
|
||||
isAdmin={isAdmin}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TerminCard({
|
||||
termin,
|
||||
userId,
|
||||
isAdmin,
|
||||
}: {
|
||||
termin: TerminWithItems;
|
||||
userId: string;
|
||||
isAdmin: boolean;
|
||||
}) {
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
const handleToggleMitbringsel = (enabled: boolean) => {
|
||||
startTransition(async () => {
|
||||
const result = await toggleMitbringselList(termin.id, enabled);
|
||||
if (result.error) {
|
||||
toast.error(result.error);
|
||||
} else {
|
||||
toast.success(
|
||||
enabled
|
||||
? "Mitbring-Liste aktiviert"
|
||||
: "Mitbring-Liste deaktiviert"
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="flex flex-col overflow-hidden relative">
|
||||
{termin.status === TerminStatus.PENDING && (
|
||||
<div className="absolute top-0 right-0 bg-yellow-500 text-white text-xs font-bold px-2 py-1 rounded-bl-lg z-10">
|
||||
Ausstehend
|
||||
</div>
|
||||
)}
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex justify-between items-start mb-2 gap-2">
|
||||
<Badge variant={getBadgeVariant(termin.type)} className={getBadgeColor(termin.type)}>
|
||||
{getTypeLabel(termin.type)}
|
||||
</Badge>
|
||||
</div>
|
||||
<CardTitle className="line-clamp-2 leading-tight">{termin.title}</CardTitle>
|
||||
<CardDescription className="flex items-center gap-1 mt-1 text-sm">
|
||||
<Clock className="h-3.5 w-3.5" />
|
||||
{format(termin.startDate, "PP", { locale: de })}
|
||||
{!termin.allDay && (
|
||||
<>
|
||||
{" • "}
|
||||
{format(termin.startDate, "p", { locale: de })} -{" "}
|
||||
{format(termin.endDate, "p", { locale: de })}
|
||||
</>
|
||||
)}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="flex-1 pb-4">
|
||||
{termin.description && (
|
||||
<div className="flex items-start gap-2 text-sm text-muted-foreground mt-2">
|
||||
<AlignLeft className="h-4 w-4 shrink-0 mt-0.5" />
|
||||
<p className="line-clamp-3 whitespace-pre-wrap">{termin.description}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Admin Toggle for Mitbringsel-List */}
|
||||
{isAdmin && termin.status === TerminStatus.CONFIRMED && (
|
||||
<div className="flex items-center space-x-2 mt-6 pt-4 border-t">
|
||||
<Switch
|
||||
id={`mitbringsel-${termin.id}`}
|
||||
checked={termin.mitbringselListEnabled}
|
||||
onCheckedChange={handleToggleMitbringsel}
|
||||
disabled={isPending}
|
||||
/>
|
||||
<Label htmlFor={`mitbringsel-${termin.id}`} className="text-xs">
|
||||
Mitbring-Liste aktiv
|
||||
</Label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Mitbringsel-List UI */}
|
||||
{termin.mitbringselListEnabled && termin.status === TerminStatus.CONFIRMED && (
|
||||
<div className="mt-4">
|
||||
<MitbringselList
|
||||
terminId={termin.id}
|
||||
items={termin.mitbringselItems || []}
|
||||
currentUserId={userId}
|
||||
isAdmin={isAdmin}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function getBadgeVariant(type: TerminType): "default" | "secondary" | "destructive" | "outline" {
|
||||
switch (type) {
|
||||
case TerminType.KITA_FEST:
|
||||
case TerminType.MITMACH_TAG:
|
||||
return "default";
|
||||
case TerminType.SCHLIESSTAG:
|
||||
case TerminType.TEAMTAG:
|
||||
return "destructive";
|
||||
case TerminType.GEBURTSTAG_INTERN:
|
||||
case TerminType.GEBURTSTAG_EXTERN:
|
||||
case TerminType.ELTERNABEND:
|
||||
case TerminType.MITGLIEDERVERSAMMLUNG:
|
||||
case TerminType.ELTERNCAFE:
|
||||
return "secondary";
|
||||
default:
|
||||
return "outline";
|
||||
}
|
||||
}
|
||||
|
||||
function getBadgeColor(type: TerminType): string {
|
||||
switch (type) {
|
||||
case TerminType.KITA_FEST:
|
||||
case TerminType.MITMACH_TAG:
|
||||
return "bg-amber-500 hover:bg-amber-600 text-white border-transparent";
|
||||
case TerminType.SCHLIESSTAG:
|
||||
case TerminType.TEAMTAG:
|
||||
return "bg-rose-500 hover:bg-rose-600 text-white border-transparent";
|
||||
case TerminType.GEBURTSTAG_INTERN:
|
||||
case TerminType.GEBURTSTAG_EXTERN:
|
||||
return "bg-blue-500 hover:bg-blue-600 text-white border-transparent";
|
||||
case TerminType.ELTERNABEND:
|
||||
case TerminType.MITGLIEDERVERSAMMLUNG:
|
||||
case TerminType.ELTERNCAFE:
|
||||
return "bg-purple-500 hover:bg-purple-600 text-white border-transparent";
|
||||
default:
|
||||
return "bg-slate-200 text-slate-800 border-slate-300 dark:bg-slate-800 dark:text-slate-200 dark:border-slate-700";
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeLabel(type: TerminType): string {
|
||||
switch (type) {
|
||||
case TerminType.KITA_FEST:
|
||||
return "Kita-Fest";
|
||||
case TerminType.MITMACH_TAG:
|
||||
return "Mitmach-Tag";
|
||||
case TerminType.SCHLIESSTAG:
|
||||
return "Schließtag";
|
||||
case TerminType.TEAMTAG:
|
||||
return "Teamtag (Kita geschlossen)";
|
||||
case TerminType.ELTERNABEND:
|
||||
return "Elternabend";
|
||||
case TerminType.MITGLIEDERVERSAMMLUNG:
|
||||
return "Mitgliederversammlung";
|
||||
case TerminType.ELTERNCAFE:
|
||||
return "Elterncafe";
|
||||
case TerminType.GEBURTSTAG_INTERN:
|
||||
return "Geburtstag (Intern)";
|
||||
case TerminType.GEBURTSTAG_EXTERN:
|
||||
return "Raumanfrage (Extern)";
|
||||
default:
|
||||
return "Sonstiges";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user