From 732f3873354863a4dec591d4d6a425edb7b47c61 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Mon, 27 Oct 2025 22:25:44 -0700 Subject: add heatmap api endpoints and heatmap to stub profile page --- frontend/src/components/Heatmap.tsx | 36 +++++++++++++++ frontend/src/pages/Profile.tsx | 88 +++++++++++++++++++++++++++++++++---- 2 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 frontend/src/components/Heatmap.tsx (limited to 'frontend/src') diff --git a/frontend/src/components/Heatmap.tsx b/frontend/src/components/Heatmap.tsx new file mode 100644 index 0000000..6720481 --- /dev/null +++ b/frontend/src/components/Heatmap.tsx @@ -0,0 +1,36 @@ +import HeatMap from '@uiw/react-heat-map'; + +export type HeatmapObject = { + date: string, + count: number +} + +export type HeatmapData = { + data: HeatmapObject[] +} + +const Heatmap = (data : HeatmapData) => { + const oneYearAgo = new Date(); + oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1); + console.log(data.data); + + return ( + + ) + +} +export default Heatmap; diff --git a/frontend/src/pages/Profile.tsx b/frontend/src/pages/Profile.tsx index 184681d..4ab5995 100644 --- a/frontend/src/pages/Profile.tsx +++ b/frontend/src/pages/Profile.tsx @@ -1,19 +1,74 @@ -import { useNavigate } from 'react-router'; -import LoadingDisplay from "../components/LoadingDisplay"; +import { useState, useEffect } from "react"; +import { useNavigate } from "react-router"; +import { isBrowser } from "react-device-detect"; +import LoadingDisplay from "../components/LoadingDisplay"; import SessionExpiredPopup from "../components/SessionExpiredPopup"; -import { NavBar } from '../components/NavBar'; +import { NavBar } from "../components/NavBar"; import { useAuth } from "../contexts/AuthContext"; - - +import Heatmap from "../components/Heatmap"; +import type { HeatmapData } from "../components/Heatmap"; const Profile = () => { const { user, isLoading, logout } = useAuth(); + const targetUser = + new URLSearchParams(window.location.search).get("userId") || ""; // looking at profile of this user const navigate = useNavigate(); + const [fetchingHeatmapData, setFetchingHeatmapData] = useState(false); + const [heatmapData, setHeatmapData] = useState({ data: [] }); + + useEffect(() => { + if (targetUser) { + setFetchingHeatmapData(true); + const fetchHeatmapData = async () => { + try { + const response = await fetch( + new URL( + import.meta.env.VITE_API_URL + "/heatmap?userId=" + targetUser, + ), + { credentials: "include" }, + ); + const data = await response.json(); + return data; + } catch (error) { + setFetchingHeatmapData(false); + console.error("Failed to fetch heatmap data:", error); + throw error; + } + }; + fetchHeatmapData().then((data) => { + const heatmapDates: { [key: string]: number } = {}; + for (let i = 0; i < data.scores.length; i++) { + const date = new Date(data.scores[i].timestamp); + const dateString = date.toDateString(); + if (!heatmapDates[dateString]) { + heatmapDates[dateString] = 1; + } else { + heatmapDates[dateString] += 1; + } + } + setHeatmapData({ + data: Object.entries(heatmapDates).map(([date, count]) => ({ + date, + count, + })), + }); + setFetchingHeatmapData(false); + }); + } + }, [targetUser]); + + if (!targetUser) { + navigate("/"); + } - if (isLoading) { + if (isLoading || fetchingHeatmapData) { return ; } + if (!user) { + return ; + } + const handleLogout = async () => { try { await logout(); @@ -30,8 +85,25 @@ const Profile = () => { return (
- -

Profile

+ + + {/* Main Content */} +
+ {/* Header */} +
+

+ {user.username} +

+

+ This is a profile page for {user.username} +

+
+ {isBrowser ? ( +
+ +
+ ) : null} +
); }; -- cgit v1.2.3