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