Initial commit

This commit is contained in:
2026-04-24 08:02:13 +02:00
commit 867c06295c
76 changed files with 10573 additions and 0 deletions
@@ -0,0 +1,120 @@
import { useEffect, useState } from 'react';
import { useStats } from '../../hooks/useStats';
import { formatMinutes } from '../../utils/time';
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
Cell,
} from 'recharts';
interface DailySummaryProps {
from_date: string;
to_date: string;
day_start: string;
day_end: string;
}
interface ChartDataItem {
date: string;
daySleep: number;
nightSleep: number;
total: number;
}
const DailySummary: React.FC<DailySummaryProps> = ({ from_date, to_date, day_start, day_end }) => {
const { dailySummary, isLoading } = useStats(from_date, to_date, day_start, day_end);
const [chartData, setChartData] = useState<ChartDataItem[]>([]);
const [avgStats, setAvgStats] = useState({ avgTotal: 0, avgDay: 0, avgNight: 0, count: 0 });
useEffect(() => {
if (!dailySummary?.days) {
setChartData([]);
setAvgStats({ avgTotal: 0, avgDay: 0, avgNight: 0, count: 0 });
return;
}
const data = dailySummary.days.map((day) => ({
date: day.date,
daySleep: day.day_minutes,
nightSleep: day.night_minutes,
total: day.total_minutes,
}));
setChartData(data.reverse());
if (data.length) {
const totals = data.reduce(
(acc, d) => ({
total: acc.total + d.total,
day: acc.day + d.daySleep,
night: acc.night + d.nightSleep,
}),
{ total: 0, day: 0, night: 0 }
);
const count = data.length;
setAvgStats({
avgTotal: Math.round(totals.total / count),
avgDay: Math.round(totals.day / count),
avgNight: Math.round(totals.night / count),
count,
});
}
}, [dailySummary]);
if (isLoading) return <div className="text-center p-4">Loading summary...</div>;
if (!chartData.length) {
return <div className="text-center p-4 text-gray-500">No data available for this period.</div>;
}
return (
<div className="bg-white p-4 rounded-xl shadow-sm border border-gray-200">
<h3 className="text-lg font-semibold mb-4 text-gray-800">Daily Summary</h3>
<ResponsiveContainer width="100%" height={Math.max(200, chartData.length * 30)}>
<BarChart
data={chartData}
layout="vertical"
margin={{ top: 5, right: 30, left: 60, bottom: 5 }}
>
<CartesianGrid strokeDasharray="3 3" stroke="#e5e7eb" />
<XAxis type="number" tick={{ fontSize: 12 }} tickLine={false} />
<YAxis
type="category"
dataKey="date"
tick={{ fontSize: 12 }}
tickLine={false}
width={60}
/>
<Tooltip
formatter={(value: number, name: string) => [
formatMinutes(value),
name === 'daySleep' ? 'Day' : 'Night',
]}
/>
<Bar dataKey="nightSleep" stackId="a" fill="#1e3a5f" />
<Bar dataKey="daySleep" stackId="a" fill="#fbbf24" />
</BarChart>
</ResponsiveContainer>
<div className="mt-4 grid grid-cols-3 gap-4 text-center">
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-xs text-gray-500">Avg Total</div>
<div className="text-lg font-semibold text-gray-800">{formatMinutes(avgStats.avgTotal)}</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-xs text-gray-500">Avg Day</div>
<div className="text-lg font-semibold text-gray-800">{formatMinutes(avgStats.avgDay)}</div>
</div>
<div className="p-3 bg-gray-50 rounded-lg">
<div className="text-xs text-gray-500">Avg Night</div>
<div className="text-lg font-semibold text-gray-800">{formatMinutes(avgStats.avgNight)}</div>
</div>
</div>
</div>
);
};
export default DailySummary;