Initial commit
This commit is contained in:
@@ -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;
|
||||
Reference in New Issue
Block a user