266 lines
7.0 KiB
TypeScript
266 lines
7.0 KiB
TypeScript
import {
|
|
DutyAssignmentStatus,
|
|
EventParticipationStatus,
|
|
TerminStatus,
|
|
UserRole,
|
|
} from "@prisma/client";
|
|
|
|
import { requireKitaSession } from "@/lib/auth-utils";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { AdminTerminModal } from "./_components/admin-termin-modal";
|
|
import { PendingAnfragen, type PendingTerminDto } from "./_components/pending-anfragen";
|
|
import { TerminList, type CalendarListItemDto } from "./_components/termin-list";
|
|
import { TerminRequestModal } from "./_components/termin-request-modal";
|
|
|
|
export default async function KalenderPage({
|
|
searchParams,
|
|
}: {
|
|
searchParams: { tab?: string };
|
|
}) {
|
|
const session = await requireKitaSession();
|
|
const isAdmin =
|
|
session.user.role === UserRole.ADMIN ||
|
|
session.user.role === UserRole.KOORDINATOR;
|
|
const familyIdForParticipation = session.user.familyId ?? "__no_family__";
|
|
|
|
const currentTab = searchParams.tab || "übersicht";
|
|
|
|
const confirmedTermineRows = await prisma.termin.findMany({
|
|
where: {
|
|
kitaId: session.user.kitaId,
|
|
status: TerminStatus.CONFIRMED,
|
|
},
|
|
select: {
|
|
id: true,
|
|
title: true,
|
|
description: true,
|
|
type: true,
|
|
status: true,
|
|
startDate: true,
|
|
endDate: true,
|
|
allDay: true,
|
|
mitbringselListEnabled: true,
|
|
requiresRsvp: true,
|
|
participantInfo: true,
|
|
mitbringselItems: {
|
|
select: {
|
|
id: true,
|
|
userId: true,
|
|
content: true,
|
|
user: {
|
|
select: {
|
|
firstName: true,
|
|
lastName: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
participations: {
|
|
where: {
|
|
child: {
|
|
familyId: familyIdForParticipation,
|
|
},
|
|
},
|
|
select: {
|
|
childId: true,
|
|
status: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: { startDate: "asc" },
|
|
});
|
|
|
|
const myPendingTermineRows = await prisma.termin.findMany({
|
|
where: {
|
|
kitaId: session.user.kitaId,
|
|
status: TerminStatus.PENDING,
|
|
createdById: session.user.id,
|
|
},
|
|
select: {
|
|
id: true,
|
|
title: true,
|
|
description: true,
|
|
type: true,
|
|
status: true,
|
|
startDate: true,
|
|
endDate: true,
|
|
allDay: true,
|
|
mitbringselListEnabled: true,
|
|
requiresRsvp: true,
|
|
participantInfo: true,
|
|
mitbringselItems: {
|
|
select: {
|
|
id: true,
|
|
userId: true,
|
|
content: true,
|
|
user: {
|
|
select: {
|
|
firstName: true,
|
|
lastName: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
participations: {
|
|
where: {
|
|
child: {
|
|
familyId: familyIdForParticipation,
|
|
},
|
|
},
|
|
select: {
|
|
childId: true,
|
|
status: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: { startDate: "asc" },
|
|
});
|
|
|
|
const dutyAssignmentRows = await prisma.dutyAssignment.findMany({
|
|
where: {
|
|
kitaId: session.user.kitaId,
|
|
status: DutyAssignmentStatus.PLANNED,
|
|
endDate: { gte: new Date() },
|
|
},
|
|
select: {
|
|
id: true,
|
|
startDate: true,
|
|
endDate: true,
|
|
status: true,
|
|
dutyType: {
|
|
select: {
|
|
name: true,
|
|
},
|
|
},
|
|
family: {
|
|
select: {
|
|
name: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: { startDate: "asc" },
|
|
});
|
|
|
|
const allUserTermine: CalendarListItemDto[] = [
|
|
...confirmedTermineRows.map((termin) => ({
|
|
...termin,
|
|
kind: "termin" as const,
|
|
showParticipantInfo:
|
|
isAdmin ||
|
|
termin.participations.some(
|
|
(participation) =>
|
|
participation.status === EventParticipationStatus.ATTENDING,
|
|
),
|
|
})),
|
|
...myPendingTermineRows.map((termin) => ({
|
|
...termin,
|
|
kind: "termin" as const,
|
|
showParticipantInfo:
|
|
isAdmin ||
|
|
termin.participations.some(
|
|
(participation) =>
|
|
participation.status === EventParticipationStatus.ATTENDING,
|
|
),
|
|
})),
|
|
...dutyAssignmentRows.map((assignment) => ({
|
|
kind: "duty" as const,
|
|
id: assignment.id,
|
|
title: assignment.dutyType.name,
|
|
familyName: assignment.family.name,
|
|
status: assignment.status,
|
|
startDate: assignment.startDate,
|
|
endDate: assignment.endDate,
|
|
})),
|
|
].sort((a, b) => a.startDate.getTime() - b.startDate.getTime());
|
|
|
|
let allPendingTermine: PendingTerminDto[] = [];
|
|
if (isAdmin) {
|
|
allPendingTermine = await prisma.termin.findMany({
|
|
where: {
|
|
kitaId: session.user.kitaId,
|
|
status: TerminStatus.PENDING,
|
|
},
|
|
select: {
|
|
id: true,
|
|
title: true,
|
|
startDate: true,
|
|
allDay: true,
|
|
createdBy: {
|
|
select: {
|
|
firstName: true,
|
|
lastName: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: { createdAt: "desc" },
|
|
});
|
|
}
|
|
|
|
return (
|
|
<div className="flex h-full flex-col gap-6 p-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-2xl font-bold tracking-tight">Terminkalender</h1>
|
|
<p className="text-muted-foreground">
|
|
Alle anstehenden Termine, Feste und Schließtage im Überblick.
|
|
</p>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<TerminRequestModal />
|
|
{isAdmin && <AdminTerminModal />}
|
|
</div>
|
|
</div>
|
|
|
|
{isAdmin ? (
|
|
<div className="flex flex-col gap-4">
|
|
<div className="flex gap-4 border-b">
|
|
<a
|
|
href="/dashboard/kalender?tab=übersicht"
|
|
className={`pb-2 text-sm font-medium transition-colors hover:text-primary ${
|
|
currentTab === "übersicht"
|
|
? "border-b-2 border-primary text-primary"
|
|
: "text-muted-foreground"
|
|
}`}
|
|
>
|
|
Übersicht
|
|
</a>
|
|
<a
|
|
href="/dashboard/kalender?tab=anfragen"
|
|
className={`flex items-center gap-2 pb-2 text-sm font-medium transition-colors hover:text-primary ${
|
|
currentTab === "anfragen"
|
|
? "border-b-2 border-primary text-primary"
|
|
: "text-muted-foreground"
|
|
}`}
|
|
>
|
|
Ausstehende Anfragen
|
|
{allPendingTermine.length > 0 && (
|
|
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground">
|
|
{allPendingTermine.length}
|
|
</span>
|
|
)}
|
|
</a>
|
|
</div>
|
|
|
|
<div className="pt-2">
|
|
{currentTab === "übersicht" ? (
|
|
<TerminList
|
|
termine={allUserTermine}
|
|
userId={session.user.id}
|
|
isAdmin={isAdmin}
|
|
/>
|
|
) : (
|
|
<PendingAnfragen termine={allPendingTermine} />
|
|
)}
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<TerminList
|
|
termine={allUserTermine}
|
|
userId={session.user.id}
|
|
isAdmin={isAdmin}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|