Files
sexy/app/(app)/sessions/[id]/page.tsx
T

61 lines
2.3 KiB
TypeScript
Raw Normal View History

import { notFound } from "next/navigation";
import type { Metadata } from "next";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { SessionTimelineChart } from "@/components/sessions/SessionTimelineChart";
import { getPlaySessionDetail, getPlaySessionName } from "@/lib/db/queries/play-sessions";
import { getSessionTimeline } from "@/lib/db/queries/stats";
export const dynamic = "force-dynamic";
export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
const { id } = await params;
const name = await getPlaySessionName(Number(id));
return { title: name ?? `Session #${id}` };
}
function formatDuration(ms: number | null): string {
if (ms === null) return "-";
const totalSeconds = Math.round(ms / 1000);
return `${Math.floor(totalSeconds / 60)}:${(totalSeconds % 60).toString().padStart(2, "0")}`;
}
export default async function SessionDetailPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const sessionId = Number(id);
const [detail, timeline] = await Promise.all([getPlaySessionDetail(sessionId), getSessionTimeline(sessionId)]);
if (!detail) notFound();
return (
<div className="flex flex-col gap-6">
<div>
<h1 className="font-heading text-2xl font-semibold">{detail.session.name ?? `Session #${detail.session.id}`}</h1>
<p className="text-sm text-muted-foreground">
{detail.session.kind} · {detail.session.status} · {formatDuration(detail.session.durationMs)}
</p>
</div>
<Card className="bp-glass">
<CardHeader>
<CardTitle className="text-base">Intensity timeline</CardTitle>
</CardHeader>
<CardContent>
<SessionTimelineChart timeline={timeline} />
</CardContent>
</Card>
<Card className="bp-glass">
<CardHeader>
<CardTitle className="text-base">Devices</CardTitle>
</CardHeader>
<CardContent className="flex flex-col gap-1">
{detail.devices.map((d) => (
<div key={d.id} className="text-sm">
{d.slotLabel} <span className="text-muted-foreground">({d.deviceDisplayName ?? d.deviceBleName})</span>
</div>
))}
</CardContent>
</Card>
</div>
);
}