|
|
|
@ -2,6 +2,15 @@ import fs from "node:fs";
|
|
|
|
import { HourChart } from "./(charts)/hour";
|
|
|
|
import { HourChart } from "./(charts)/hour";
|
|
|
|
import { DayChart } from "./(charts)/day";
|
|
|
|
import { DayChart } from "./(charts)/day";
|
|
|
|
import { MinuteChart } from "./(charts)/minute";
|
|
|
|
import { MinuteChart } from "./(charts)/minute";
|
|
|
|
|
|
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
|
|
|
Card,
|
|
|
|
|
|
|
|
CardContent,
|
|
|
|
|
|
|
|
CardFooter,
|
|
|
|
|
|
|
|
CardHeader,
|
|
|
|
|
|
|
|
CardTitle,
|
|
|
|
|
|
|
|
} from "@/components/ui/card";
|
|
|
|
|
|
|
|
|
|
|
|
export default async function Home() {
|
|
|
|
export default async function Home() {
|
|
|
|
const file = await fs.promises.readFile("./output.txt");
|
|
|
|
const file = await fs.promises.readFile("./output.txt");
|
|
|
|
@ -9,20 +18,264 @@ export default async function Home() {
|
|
|
|
const lines = file.toString().split("\n");
|
|
|
|
const lines = file.toString().split("\n");
|
|
|
|
|
|
|
|
|
|
|
|
const data = lines.map((line) => {
|
|
|
|
const data = lines.map((line) => {
|
|
|
|
const [timestamp, event, value] = line.split(",");
|
|
|
|
const [timestamp, _, value] = line.split(",");
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
timestamp: Math.round(parseFloat(timestamp) * 1000),
|
|
|
|
timestamp: Math.round(parseFloat(timestamp) * 1000),
|
|
|
|
foldtime: parseFloat(value),
|
|
|
|
foldtime: parseFloat(value),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
console.log(data);
|
|
|
|
const thisMonthData = convertDataToThisMonthPerDay(data);
|
|
|
|
|
|
|
|
const thisHourData = convertDataToThisHourPerMinute(data);
|
|
|
|
|
|
|
|
const todayData = convertDataToTodayPerHour(data);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<main className="flex-grow w-full flex flex-col justify-center gap-4 items-center p-4">
|
|
|
|
<main className="flex-grow w-full flex flex-col justify-center gap-4 items-center p-4">
|
|
|
|
<MinuteChart data={data} />
|
|
|
|
<div className="p-4 w-full bg-accent max-w-[1200px] rounded-xl flex justify-start gap-4">
|
|
|
|
<HourChart data={data} />
|
|
|
|
<div className="flex flex-col gap-2 items-start p-4">
|
|
|
|
<DayChart data={data} />
|
|
|
|
<span className="text-muted-foreground">This Month</span>
|
|
|
|
|
|
|
|
<h2 className="text-2xl font-bold">
|
|
|
|
|
|
|
|
{thisMonthData.reduce((acc, curr) => {
|
|
|
|
|
|
|
|
return acc + 1;
|
|
|
|
|
|
|
|
}, 0)}
|
|
|
|
|
|
|
|
{" Towel(s)"}
|
|
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
|
|
<span className="text-muted-foreground">
|
|
|
|
|
|
|
|
Avg Fold Time (s):{" "}
|
|
|
|
|
|
|
|
{thisMonthData.reduce((acc, curr) => {
|
|
|
|
|
|
|
|
return acc + curr.foldtime;
|
|
|
|
|
|
|
|
}, 0) / thisMonthData.length || 0}
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-2 items-start p-4">
|
|
|
|
|
|
|
|
<span className="text-muted-foreground">Today</span>
|
|
|
|
|
|
|
|
<h2 className="text-2xl font-bold">
|
|
|
|
|
|
|
|
{todayData.reduce((acc, curr) => {
|
|
|
|
|
|
|
|
return acc + 1;
|
|
|
|
|
|
|
|
}, 0)}
|
|
|
|
|
|
|
|
{" Towel(s)"}
|
|
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
|
|
<span className="text-muted-foreground">
|
|
|
|
|
|
|
|
Avg Fold Time (s):{" "}
|
|
|
|
|
|
|
|
{todayData.reduce((acc, curr) => {
|
|
|
|
|
|
|
|
return acc + curr.foldtime;
|
|
|
|
|
|
|
|
}, 0) / todayData.length || 0}
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-2 items-start p-4">
|
|
|
|
|
|
|
|
<span className="text-muted-foreground">This Month</span>
|
|
|
|
|
|
|
|
<h2 className="text-2xl font-bold">
|
|
|
|
|
|
|
|
{thisMonthData.reduce((acc, curr) => {
|
|
|
|
|
|
|
|
return acc + 1;
|
|
|
|
|
|
|
|
}, 0)}
|
|
|
|
|
|
|
|
{" Towel(s)"}
|
|
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
|
|
<span className="text-muted-foreground">
|
|
|
|
|
|
|
|
Avg Fold Time (s):{" "}
|
|
|
|
|
|
|
|
{thisHourData.reduce((acc, curr) => {
|
|
|
|
|
|
|
|
return acc + curr.foldtime;
|
|
|
|
|
|
|
|
}, 0) / thisHourData.length || 0}
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<Card className="w-full max-w-[1200px]">
|
|
|
|
|
|
|
|
<Tabs defaultValue="month" className="w-full">
|
|
|
|
|
|
|
|
<CardHeader>
|
|
|
|
|
|
|
|
<TabsList className="w-full">
|
|
|
|
|
|
|
|
<TabsTrigger className="w-full" value="month">
|
|
|
|
|
|
|
|
Month
|
|
|
|
|
|
|
|
</TabsTrigger>
|
|
|
|
|
|
|
|
<TabsTrigger className="w-full" value="day">
|
|
|
|
|
|
|
|
Day
|
|
|
|
|
|
|
|
</TabsTrigger>
|
|
|
|
|
|
|
|
<TabsTrigger className="w-full" value="hour">
|
|
|
|
|
|
|
|
Hour
|
|
|
|
|
|
|
|
</TabsTrigger>
|
|
|
|
|
|
|
|
</TabsList>
|
|
|
|
|
|
|
|
</CardHeader>
|
|
|
|
|
|
|
|
<CardContent>
|
|
|
|
|
|
|
|
<TabsContent value="month">
|
|
|
|
|
|
|
|
<DayChart
|
|
|
|
|
|
|
|
chartData={convertDataToThisMonthPerDayChartData(
|
|
|
|
|
|
|
|
thisMonthData
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</TabsContent>
|
|
|
|
|
|
|
|
<TabsContent value="day">
|
|
|
|
|
|
|
|
<HourChart
|
|
|
|
|
|
|
|
chartData={convertDataToTodayPerHourChartData(
|
|
|
|
|
|
|
|
todayData
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</TabsContent>
|
|
|
|
|
|
|
|
<TabsContent value="hour">
|
|
|
|
|
|
|
|
<MinuteChart
|
|
|
|
|
|
|
|
chartData={convertDataToThisHourPerMinuteChartData(
|
|
|
|
|
|
|
|
thisHourData
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</TabsContent>
|
|
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
|
|
<CardFooter></CardFooter>
|
|
|
|
|
|
|
|
</Tabs>
|
|
|
|
|
|
|
|
</Card>
|
|
|
|
</main>
|
|
|
|
</main>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const convertDataToThisMonthPerDay = (
|
|
|
|
|
|
|
|
data: { timestamp: number; foldtime: number }[]
|
|
|
|
|
|
|
|
) => {
|
|
|
|
|
|
|
|
const thisMonthTimestamp = new Date();
|
|
|
|
|
|
|
|
thisMonthTimestamp.setHours(0, 0, 0, 0);
|
|
|
|
|
|
|
|
thisMonthTimestamp.setDate(1);
|
|
|
|
|
|
|
|
const nextMonthTimestamp = new Date();
|
|
|
|
|
|
|
|
nextMonthTimestamp.setHours(0, 0, 0, 0);
|
|
|
|
|
|
|
|
nextMonthTimestamp.setDate(1);
|
|
|
|
|
|
|
|
nextMonthTimestamp.setMonth(nextMonthTimestamp.getMonth() + 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log(thisMonthTimestamp.getTime(), nextMonthTimestamp.getTime());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const thisMonthData = data.filter(
|
|
|
|
|
|
|
|
(data) =>
|
|
|
|
|
|
|
|
data.timestamp >= thisMonthTimestamp.getTime() &&
|
|
|
|
|
|
|
|
data.timestamp < nextMonthTimestamp.getTime()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return thisMonthData;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const convertDataToThisMonthPerDayChartData = (
|
|
|
|
|
|
|
|
data: { timestamp: number; foldtime: number }[]
|
|
|
|
|
|
|
|
) => {
|
|
|
|
|
|
|
|
const todayDataPerHour = data.reduce((acc, data) => {
|
|
|
|
|
|
|
|
const day = new Date(data.timestamp).getDate();
|
|
|
|
|
|
|
|
if (!acc[day]) {
|
|
|
|
|
|
|
|
acc[day] = {
|
|
|
|
|
|
|
|
count: 0,
|
|
|
|
|
|
|
|
foldTime: 0,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
acc[day].count += 1;
|
|
|
|
|
|
|
|
acc[day].foldTime += data.foldtime;
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
|
|
|
}, {} as Record<number, { count: number; foldTime: number }>);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const thisMonthDays = new Date();
|
|
|
|
|
|
|
|
thisMonthDays.setMonth(thisMonthDays.getMonth() + 1);
|
|
|
|
|
|
|
|
thisMonthDays.setDate(1);
|
|
|
|
|
|
|
|
thisMonthDays.setDate(thisMonthDays.getDate() - 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const chartData = new Array(thisMonthDays.getDate()).fill(0).map((_, i) => {
|
|
|
|
|
|
|
|
const day = i + 1;
|
|
|
|
|
|
|
|
if (!todayDataPerHour[day])
|
|
|
|
|
|
|
|
return { day: "Day " + day, value: 0, foldtime: 0 };
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
day: "Day " + day,
|
|
|
|
|
|
|
|
value: todayDataPerHour[day].count,
|
|
|
|
|
|
|
|
foldtime:
|
|
|
|
|
|
|
|
todayDataPerHour[day].foldTime / todayDataPerHour[day].count,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return chartData;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const convertDataToThisHourPerMinute = (
|
|
|
|
|
|
|
|
data: { timestamp: number; foldtime: number }[]
|
|
|
|
|
|
|
|
) => {
|
|
|
|
|
|
|
|
const thisHourTimestamp = new Date();
|
|
|
|
|
|
|
|
thisHourTimestamp.setMinutes(0, 0, 0);
|
|
|
|
|
|
|
|
const nextHourTimestamp = new Date();
|
|
|
|
|
|
|
|
nextHourTimestamp.setHours(nextHourTimestamp.getHours() + 1);
|
|
|
|
|
|
|
|
nextHourTimestamp.setMinutes(0, 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log(thisHourTimestamp.getTime(), nextHourTimestamp.getTime());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const todayData = data.filter(
|
|
|
|
|
|
|
|
(data) =>
|
|
|
|
|
|
|
|
data.timestamp >= thisHourTimestamp.getTime() &&
|
|
|
|
|
|
|
|
data.timestamp < nextHourTimestamp.getTime()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return todayData;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const convertDataToThisHourPerMinuteChartData = (
|
|
|
|
|
|
|
|
data: { timestamp: number; foldtime: number }[]
|
|
|
|
|
|
|
|
) => {
|
|
|
|
|
|
|
|
const todayDataPerHour = data.reduce((acc, data) => {
|
|
|
|
|
|
|
|
const hour = new Date(data.timestamp).getMinutes();
|
|
|
|
|
|
|
|
if (!acc[hour]) {
|
|
|
|
|
|
|
|
acc[hour] = {
|
|
|
|
|
|
|
|
count: 0,
|
|
|
|
|
|
|
|
foldTime: 0,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
acc[hour].count += 1;
|
|
|
|
|
|
|
|
acc[hour].foldTime += data.foldtime;
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
|
|
|
}, {} as Record<number, { count: number; foldTime: number }>);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const chartData = new Array(60).fill(0).map((_, i) => {
|
|
|
|
|
|
|
|
if (!todayDataPerHour[i])
|
|
|
|
|
|
|
|
return { minute: "Minute " + i, value: 0, foldtime: 0 };
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
minute: "Minute " + i,
|
|
|
|
|
|
|
|
value: todayDataPerHour[i].count,
|
|
|
|
|
|
|
|
foldtime: todayDataPerHour[i].foldTime / todayDataPerHour[i].count,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return chartData;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const convertDataToTodayPerHour = (
|
|
|
|
|
|
|
|
data: { timestamp: number; foldtime: number }[]
|
|
|
|
|
|
|
|
) => {
|
|
|
|
|
|
|
|
const todayTimestamp = new Date();
|
|
|
|
|
|
|
|
todayTimestamp.setHours(0, 0, 0, 0);
|
|
|
|
|
|
|
|
const tomorrowTimestamp = new Date();
|
|
|
|
|
|
|
|
tomorrowTimestamp.setHours(0, 0, 0, 0);
|
|
|
|
|
|
|
|
tomorrowTimestamp.setDate(tomorrowTimestamp.getDate() + 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log(todayTimestamp.getTime(), tomorrowTimestamp.getTime());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const todayData = data.filter(
|
|
|
|
|
|
|
|
(data) =>
|
|
|
|
|
|
|
|
data.timestamp >= todayTimestamp.getTime() &&
|
|
|
|
|
|
|
|
data.timestamp < tomorrowTimestamp.getTime()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return todayData;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const convertDataToTodayPerHourChartData = (
|
|
|
|
|
|
|
|
data: { timestamp: number; foldtime: number }[]
|
|
|
|
|
|
|
|
) => {
|
|
|
|
|
|
|
|
const todayDataPerHour = data.reduce((acc, data) => {
|
|
|
|
|
|
|
|
const hour = new Date(data.timestamp).getHours();
|
|
|
|
|
|
|
|
if (!acc[hour]) {
|
|
|
|
|
|
|
|
acc[hour] = {
|
|
|
|
|
|
|
|
count: 0,
|
|
|
|
|
|
|
|
foldTime: 0,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
acc[hour].count += 1;
|
|
|
|
|
|
|
|
acc[hour].foldTime += data.foldtime;
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
|
|
|
}, {} as Record<number, { count: number; foldTime: number }>);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const chartData = new Array(24).fill(0).map((_, i) => {
|
|
|
|
|
|
|
|
if (!todayDataPerHour[i])
|
|
|
|
|
|
|
|
return { hour: i + 1 + ":00", value: 0, foldtime: 0 };
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
hour: i + 1 + ":00",
|
|
|
|
|
|
|
|
value: todayDataPerHour[i].count,
|
|
|
|
|
|
|
|
foldtime: todayDataPerHour[i].foldTime / todayDataPerHour[i].count,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return chartData;
|
|
|
|
|
|
|
|
};
|
|
|
|
|