diff --git a/frontend/src/pages/Stats.tsx b/frontend/src/pages/Stats.tsx
index 29a177c..3b6b21f 100644
--- a/frontend/src/pages/Stats.tsx
+++ b/frontend/src/pages/Stats.tsx
@@ -10,13 +10,18 @@ import {
ResponsiveContainer
} from "recharts";
import WordCloud from "../stats/WordCloud";
+import ActivityHeatmap from "../stats/ActivityHeatmap";
+
const StatPage = () => {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
+ const [heatmapData, setHeatmapData] = useState([]);
+
useEffect(() => {
+ // Posts per Day
axios
.get("http://localhost:5000/stats/posts_per_day")
.then(res => {
@@ -27,6 +32,18 @@ const StatPage = () => {
setError(err.response?.data?.error || "Failed to load data");
setLoading(false);
});
+
+ // Heatmap
+ axios
+ .get("http://localhost:5000/stats/heatmap")
+ .then(res => {
+ setHeatmapData(res.data);
+ setLoading(false);
+ })
+ .catch(err => {
+ setError(err.response?.data?.error || "Failed to load heatmap data");
+ setLoading(false);
+ });
}, []);
if (loading) return
Loading posts per day…
;
@@ -52,6 +69,10 @@ const StatPage = () => {
Word Cloud
+
+ Heatmap
+
+
);
}
diff --git a/frontend/src/stats/ActivityHeatmap.tsx b/frontend/src/stats/ActivityHeatmap.tsx
new file mode 100644
index 0000000..38322e0
--- /dev/null
+++ b/frontend/src/stats/ActivityHeatmap.tsx
@@ -0,0 +1,65 @@
+import { ResponsiveHeatMap } from "@nivo/heatmap";
+
+type ApiRow = Record;
+type ActivityHeatmapProps = {
+ data: ApiRow[];
+};
+
+type ChartPoint = {
+ x: string;
+ y: number;
+};
+
+type ChartSeries = {
+ id: string;
+ data: ChartPoint[];
+};
+
+const DAYS = [
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday",
+ "Sunday",
+];
+
+const hourLabel = (h: number) =>
+ `${h.toString().padStart(2, "0")}:00`;
+
+const convertWeeklyData = (dataset: ApiRow[]): ChartSeries[] => {
+ return dataset.map((dayData, index) => ({
+ id: DAYS[index] ?? `Day ${index + 1}`,
+ data: Object.entries(dayData)
+ .sort(([a], [b]) => Number(a) - Number(b)) // ensure 0 → 23
+ .map(([hour, value]) => ({
+ x: hourLabel(Number(hour)),
+ y: value,
+ })),
+ }));
+};
+
+
+const ActivityHeatmap = ({ data }: ActivityHeatmapProps) => {
+ const convertedData = convertWeeklyData(data);
+
+ return (
+
+ )
+}
+
+export default ActivityHeatmap;
\ No newline at end of file