Files
myeasycms-v2/apps/web/app/[locale]/home/[account]/courses/[courseId]/page.tsx
2026-03-29 19:44:57 +02:00

189 lines
7.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Link from 'next/link';
import { GraduationCap, Users, Calendar, Euro, User, Clock } from 'lucide-react';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { Badge } from '@kit/ui/badge';
import { Button } from '@kit/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
import { createCourseManagementApi } from '@kit/course-management/api';
import { CmsPageShell } from '~/components/cms-page-shell';
interface PageProps {
params: Promise<{ account: string; courseId: string }>;
}
const STATUS_LABEL: Record<string, string> = {
planned: 'Geplant', open: 'Offen', running: 'Laufend',
completed: 'Abgeschlossen', cancelled: 'Abgesagt',
};
const STATUS_VARIANT: Record<string, 'secondary' | 'default' | 'info' | 'outline' | 'destructive'> = {
planned: 'secondary', open: 'default', running: 'info',
completed: 'outline', cancelled: 'destructive',
};
export default async function CourseDetailPage({ params }: PageProps) {
const { account, courseId } = await params;
const client = getSupabaseServerClient();
const api = createCourseManagementApi(client);
const [course, participants, sessions] = await Promise.all([
api.getCourse(courseId),
api.getParticipants(courseId),
api.getSessions(courseId),
]);
if (!course) return <div>Kurs nicht gefunden</div>;
const c = course as Record<string, unknown>;
return (
<CmsPageShell account={account} title={String(c.name)}>
<div className="flex w-full flex-col gap-6">
{/* Summary Cards */}
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
<Card>
<CardContent className="flex items-center gap-3 p-4">
<GraduationCap className="h-5 w-5 text-primary" />
<div>
<p className="text-xs text-muted-foreground">Name</p>
<p className="font-semibold">{String(c.name)}</p>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="flex items-center gap-3 p-4">
<Clock className="h-5 w-5 text-primary" />
<div>
<p className="text-xs text-muted-foreground">Status</p>
<Badge variant={STATUS_VARIANT[String(c.status)] ?? 'secondary'}>
{STATUS_LABEL[String(c.status)] ?? String(c.status)}
</Badge>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="flex items-center gap-3 p-4">
<User className="h-5 w-5 text-primary" />
<div>
<p className="text-xs text-muted-foreground">Dozent</p>
<p className="font-semibold">{String(c.instructor_id ?? '—')}</p>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="flex items-center gap-3 p-4">
<Calendar className="h-5 w-5 text-primary" />
<div>
<p className="text-xs text-muted-foreground">Beginn Ende</p>
<p className="font-semibold">
{c.start_date ? new Date(String(c.start_date)).toLocaleDateString('de-DE') : '—'}
{' '}
{c.end_date ? new Date(String(c.end_date)).toLocaleDateString('de-DE') : '—'}
</p>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="flex items-center gap-3 p-4">
<Euro className="h-5 w-5 text-primary" />
<div>
<p className="text-xs text-muted-foreground">Gebühr</p>
<p className="font-semibold">
{c.fee != null ? `${Number(c.fee).toFixed(2)}` : '—'}
</p>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="flex items-center gap-3 p-4">
<Users className="h-5 w-5 text-primary" />
<div>
<p className="text-xs text-muted-foreground">Teilnehmer</p>
<p className="font-semibold">
{participants.length} / {String(c.capacity ?? '∞')}
</p>
</div>
</CardContent>
</Card>
</div>
{/* Teilnehmer Section */}
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Teilnehmer</CardTitle>
<Link href={`/home/${account}/courses/${courseId}/participants`}>
<Button variant="outline" size="sm">Alle anzeigen</Button>
</Link>
</CardHeader>
<CardContent>
<div className="rounded-md border">
<table className="w-full text-sm">
<thead>
<tr className="border-b bg-muted/50">
<th className="p-3 text-left font-medium">Name</th>
<th className="p-3 text-left font-medium">E-Mail</th>
<th className="p-3 text-left font-medium">Status</th>
<th className="p-3 text-left font-medium">Datum</th>
</tr>
</thead>
<tbody>
{participants.length === 0 ? (
<tr><td colSpan={4} className="p-6 text-center text-muted-foreground">Keine Teilnehmer</td></tr>
) : participants.map((p: Record<string, unknown>) => (
<tr key={String(p.id)} className="border-b hover:bg-muted/30">
<td className="p-3 font-medium">{String(p.last_name ?? '')}, {String(p.first_name ?? '')}</td>
<td className="p-3">{String(p.email ?? '—')}</td>
<td className="p-3"><Badge variant="outline">{String(p.status ?? '—')}</Badge></td>
<td className="p-3">{p.enrolled_at ? new Date(String(p.enrolled_at)).toLocaleDateString('de-DE') : '—'}</td>
</tr>
))}
</tbody>
</table>
</div>
</CardContent>
</Card>
{/* Termine Section */}
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Termine</CardTitle>
<Link href={`/home/${account}/courses/${courseId}/attendance`}>
<Button variant="outline" size="sm">Anwesenheit</Button>
</Link>
</CardHeader>
<CardContent>
<div className="rounded-md border">
<table className="w-full text-sm">
<thead>
<tr className="border-b bg-muted/50">
<th className="p-3 text-left font-medium">Datum</th>
<th className="p-3 text-left font-medium">Beginn</th>
<th className="p-3 text-left font-medium">Ende</th>
<th className="p-3 text-left font-medium">Abgesagt?</th>
</tr>
</thead>
<tbody>
{sessions.length === 0 ? (
<tr><td colSpan={4} className="p-6 text-center text-muted-foreground">Keine Termine</td></tr>
) : sessions.map((s: Record<string, unknown>) => (
<tr key={String(s.id)} className="border-b hover:bg-muted/30">
<td className="p-3">{s.session_date ? new Date(String(s.session_date)).toLocaleDateString('de-DE') : '—'}</td>
<td className="p-3">{String(s.start_time ?? '—')}</td>
<td className="p-3">{String(s.end_time ?? '—')}</td>
<td className="p-3">{s.cancelled ? <Badge variant="destructive">Ja</Badge> : '—'}</td>
</tr>
))}
</tbody>
</table>
</div>
</CardContent>
</Card>
</div>
</CmsPageShell>
);
}