Add RSVP events and Unsplash image support

This commit is contained in:
t.indorf
2026-05-15 21:28:36 +02:00
parent ed6786b6ea
commit 9542def530
13 changed files with 1392 additions and 34 deletions
@@ -3,7 +3,7 @@
import { DutyAssignmentStatus, TerminStatus, TerminType } from "@prisma/client";
import { format } from "date-fns";
import { de } from "date-fns/locale";
import { AlignLeft, Calendar, Clock, WashingMachine } from "lucide-react";
import { AlertTriangle, AlignLeft, Calendar, Clock, WashingMachine } from "lucide-react";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
@@ -13,6 +13,15 @@ import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import { useTransition } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
export type TerminListItemDto = {
kind: "termin";
@@ -25,6 +34,9 @@ export type TerminListItemDto = {
endDate: Date;
allDay: boolean;
mitbringselListEnabled: boolean;
requiresRsvp: boolean;
participantInfo: string | null;
showParticipantInfo: boolean;
mitbringselItems?: {
id: string;
userId: string;
@@ -178,6 +190,8 @@ function TerminCard({
</div>
)}
<TerminDetailDialog termin={termin} />
{/* Admin Toggle for Mitbringsel-List */}
{isAdmin && termin.status === TerminStatus.CONFIRMED && (
<div className="flex items-center space-x-2 mt-6 pt-4 border-t">
@@ -209,6 +223,58 @@ function TerminCard({
);
}
function TerminDetailDialog({ termin }: { termin: TerminListItemDto }) {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline" size="sm" className="mt-4">
Details
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>{termin.title}</DialogTitle>
<DialogDescription>
{format(termin.startDate, "PP", { locale: de })}
{!termin.allDay &&
` · ${format(termin.startDate, "p", { locale: de })} - ${format(
termin.endDate,
"p",
{ locale: de },
)}`}
</DialogDescription>
</DialogHeader>
<div className="grid gap-4">
<Badge variant={getBadgeVariant(termin.type)} className={getBadgeColor(termin.type)}>
{getTypeLabel(termin.type)}
</Badge>
{termin.description ? (
<p className="whitespace-pre-wrap text-sm text-muted-foreground">
{termin.description}
</p>
) : (
<p className="text-sm text-muted-foreground">
Keine Beschreibung hinterlegt.
</p>
)}
{termin.participantInfo && termin.showParticipantInfo && (
<div className="rounded-md border border-yellow-300 bg-yellow-50 p-4 text-sm text-yellow-950">
<div className="mb-1 flex items-center gap-2 font-medium">
<AlertTriangle className="h-4 w-4 text-yellow-700" />
Wichtiger Hinweis für Teilnehmer
</div>
<p className="whitespace-pre-wrap">{termin.participantInfo}</p>
</div>
)}
</div>
</DialogContent>
</Dialog>
);
}
function getBadgeVariant(type: TerminType): "default" | "secondary" | "destructive" | "outline" {
switch (type) {
case TerminType.KITA_FEST: