Files
kalendartool/app/dashboard/page.tsx

147 lines
4.7 KiB
TypeScript

/**
* Dashboard (plan.md Abschnitt 14).
*
* User: sieht genau seinen einen Kalender als Karte (oeffnet die
* Kalenderuebersicht im Modal). Reservieren ja, verwalten nein.
* Admin: sieht alle Kalender als Karten; Klick oeffnet die
* Kalenderuebersicht, der Stift die Verwaltung (Einstellungen,
* Mitglieder, Regeln). Nur Admins erstellen/bearbeiten Kalender.
*/
import { redirect } from 'next/navigation';
import { prisma } from '@/lib/db/client';
import { requireDbUser } from '@/lib/api/context';
import { Card } from '@/components/ui/ui';
import { AppShell } from '@/components/layout/AppShell';
import { DashboardCalendarGrid } from '@/components/dashboard/DashboardCalendarGrid';
import type { ManagedCalendar } from '@/components/admin/CalendarManager';
export default async function DashboardPage() {
const user = await requireDbUser().catch(() => null);
if (!user) {
redirect('/login');
}
const membership = await prisma.calendarMember.findUnique({
where: { userId: user.id },
select: {
calendar: {
select: {
id: true,
title: true,
description: true,
timezone: true,
isActive: true,
maxReservationMinutes: true,
showTitleToMembers: true,
showNotesToMembers: true,
owner: { select: { email: true, username: true } },
_count: { select: { members: true, reservations: true } },
},
},
},
});
const ownedCalendars =
user.role === 'ADMIN'
? await prisma.calendar.findMany({
orderBy: { createdAt: 'desc' },
select: {
id: true,
title: true,
description: true,
timezone: true,
isActive: true,
maxReservationMinutes: true,
showTitleToMembers: true,
showNotesToMembers: true,
owner: { select: { email: true, username: true } },
_count: { select: { members: true, reservations: true } },
},
})
: [];
/** Vereinheitlicht DB-Zeilen auf das Karten-Datenformat. */
function toManagedCalendar(row: {
id: string;
title: string;
description: string | null;
timezone: string;
isActive: boolean;
maxReservationMinutes: number;
showTitleToMembers: boolean;
showNotesToMembers: boolean;
owner: { email: string; username: string | null };
_count: { members: number; reservations: number };
}): ManagedCalendar {
return {
id: row.id,
title: row.title,
description: row.description,
timezone: row.timezone,
isActive: row.isActive,
ownerEmail: row.owner.username ?? row.owner.email,
isOwn: true,
memberCount: row._count.members,
reservationCount: row._count.reservations,
maxReservationMinutes: row.maxReservationMinutes,
showTitleToMembers: row.showTitleToMembers,
showNotesToMembers: row.showNotesToMembers,
};
}
const adminCalendars = ownedCalendars.map(toManagedCalendar);
const userCalendar = membership?.calendar
? [toManagedCalendar(membership.calendar)]
: [];
return (
<AppShell role={user.role} userEmail={user.email} username={user.username}>
<header className="mb-8">
<h1 className="text-2xl font-bold">Dashboard</h1>
</header>
{/* User-Ansicht: genau ein Kalender (als Karte) */}
{user.role === 'USER' && (
<section>
<h2 className="mb-4 text-lg font-semibold">Mein Kalender</h2>
{userCalendar.length === 0 ? (
<Card>
<p className="text-sm text-slate-600 dark:text-slate-400">
Du bist noch keinem Kalender zugeordnet. Bitte wende dich an den
Administrator, damit er dich einem Kalender zuordnet.
</p>
</Card>
) : (
<DashboardCalendarGrid
calendars={userCalendar}
currentUserId={user.id}
isAdmin={false}
/>
)}
</section>
)}
{/* Admin-Ansicht: alle Kalender als Karten (Verwaltung) */}
{user.role === 'ADMIN' && (
<section>
<h2 className="mb-4 text-lg font-semibold">Kalender</h2>
{adminCalendars.length === 0 ? (
<Card>
<p className="text-sm text-slate-600 dark:text-slate-400">
Noch keine Kalender vorhanden. Erstelle deinen ersten Kalender
unter &quot;Kalender verwalten&quot;.
</p>
</Card>
) : (
<DashboardCalendarGrid
calendars={adminCalendars}
currentUserId={user.id}
isAdmin={true}
/>
)}
</section>
)}
</AppShell>
);
}