2026-08-25 07:51:38 +02:00
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
|
|
|
|
|
|
|
|
|
|
export interface SessionsSummary {
|
|
|
|
|
|
count: number;
|
|
|
|
|
|
totalDurationMs: number;
|
|
|
|
|
|
avgDurationMs: number;
|
2026-08-27 21:38:51 +02:00
|
|
|
|
totalReplays: number;
|
2026-08-25 07:51:38 +02:00
|
|
|
|
durationPerDevice: { deviceId: number; displayName: string | null; bleName: string; totalActiveMs: number }[];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function formatHours(ms: number): string {
|
|
|
|
|
|
return `${(ms / 3_600_000).toFixed(1)}h`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-30 20:31:31 +02:00
|
|
|
|
function formatReplays(count: number): string {
|
|
|
|
|
|
return count === 0 ? "-" : `${count}×`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-25 07:51:38 +02:00
|
|
|
|
export function SessionsSummaryCards({ summary }: { summary: SessionsSummary }) {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="flex flex-col gap-4">
|
2026-08-30 20:31:31 +02:00
|
|
|
|
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
2026-08-25 07:51:38 +02:00
|
|
|
|
<Card className="bp-glass">
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle className="text-sm text-muted-foreground">Completed sessions</CardTitle>
|
|
|
|
|
|
</CardHeader>
|
2026-08-25 16:43:28 +02:00
|
|
|
|
<CardContent className="bp-readout text-3xl">{summary.count}</CardContent>
|
2026-08-25 07:51:38 +02:00
|
|
|
|
</Card>
|
|
|
|
|
|
<Card className="bp-glass">
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle className="text-sm text-muted-foreground">Total time</CardTitle>
|
|
|
|
|
|
</CardHeader>
|
2026-08-25 16:43:28 +02:00
|
|
|
|
<CardContent className="bp-readout text-3xl">{formatHours(summary.totalDurationMs)}</CardContent>
|
2026-08-25 07:51:38 +02:00
|
|
|
|
</Card>
|
|
|
|
|
|
<Card className="bp-glass">
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle className="text-sm text-muted-foreground">Avg session length</CardTitle>
|
|
|
|
|
|
</CardHeader>
|
2026-08-25 16:43:28 +02:00
|
|
|
|
<CardContent className="bp-readout text-3xl">
|
2026-08-25 07:51:38 +02:00
|
|
|
|
{Math.round(summary.avgDurationMs / 60_000)}m
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
2026-08-30 20:31:31 +02:00
|
|
|
|
<Card className="bp-glass">
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle className="text-sm text-muted-foreground">Replays</CardTitle>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent className="bp-readout text-3xl">{formatReplays(summary.totalReplays)}</CardContent>
|
|
|
|
|
|
</Card>
|
2026-08-25 07:51:38 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
{summary.durationPerDevice.length > 0 && (
|
|
|
|
|
|
<Card className="bp-glass">
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle className="text-base">Duration per device</CardTitle>
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
<CardContent className="flex flex-col gap-2">
|
|
|
|
|
|
{summary.durationPerDevice.map((d) => (
|
|
|
|
|
|
<div key={d.deviceId} className="flex items-center justify-between text-sm">
|
|
|
|
|
|
<span>{d.displayName ?? d.bleName}</span>
|
|
|
|
|
|
<span className="text-muted-foreground">{formatHours(d.totalActiveMs)}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|