From 934062eba1c6b73bbf960f010e04b7c098649522 Mon Sep 17 00:00:00 2001 From: seventhriver <129530873+seventhriver@users.noreply.github.com> Date: Fri, 27 Feb 2026 19:53:51 -0600 Subject: [PATCH 1/3] Display user id and allow signout on profile --- app/profile/page.tsx | 91 ++++++++++++++++++++++++++++++++++++++------ util/api.ts | 12 +++++- util/types.ts | 6 +++ 3 files changed, 97 insertions(+), 12 deletions(-) diff --git a/app/profile/page.tsx b/app/profile/page.tsx index a432b4c9..68907b5d 100644 --- a/app/profile/page.tsx +++ b/app/profile/page.tsx @@ -12,7 +12,9 @@ import { loadAdmissionRSVP, loadProfile, loadQRCode, - updateProfile + updateProfile, + getUserInfo, + webSignOutUser } from "@/util/api"; import Loading from "@/components/Loading/Loading"; import ErrorSnackbar from "@/components/ErrorSnackbar/ErrorSnackbar"; @@ -46,6 +48,8 @@ export default function Profile() { const [showQR, setShowQR] = useState(false); const [qrInfo, setQrInfo] = useState(""); const [qrLoading, setQrLoading] = useState(false); + const [userId, setUserId] = useState(null); + const [signOutPopupActive, setSignOutPopupActive] = useState(false); const avatarUrl = `${base}/${avatarId}.png`; @@ -80,12 +84,13 @@ export default function Profile() { fetchQRCode(); }; - // Auto-refresh QR code every 5 minutes while the dialog is open - useEffect(() => { - if (!showQR) return; - const interval = setInterval(fetchQRCode, 5 * 60 * 1000); - return () => clearInterval(interval); - }, [showQR, fetchQRCode]); + const signOutUser = + // Auto-refresh QR code every 5 minutes while the dialog is open + useEffect(() => { + if (!showQR) return; + const interval = setInterval(fetchQRCode, 5 * 60 * 1000); + return () => clearInterval(interval); + }, [showQR, fetchQRCode]); const confirmAvatarPicker = async () => { setLoading(true); @@ -105,8 +110,34 @@ export default function Profile() { }; useEffect(() => { - // TODO: Remove this redirect once the rest of RSVP is finished. - // redirect("/"); + const loadUserInfo = async () => { + try { + const userInfo = await getUserInfo(); + console.log(userInfo); + + // if ( + // RSVPInfo.response !== "ACCEPTED" || + // RSVPInfo.status !== "ACCEPTED" + // ) { + // router.push("/profile-unavailable"); + // return; + // } + // const profile = await loadProfile(); + // setAvatarId( + // profile.avatarUrl.split("/").pop()!.replace(".png", "") + // ); + setUserId(userInfo.userId); + + setLoading(false); + } catch (error: any) { + console.error("Error loading user data:", error); + setLoading(false); + } + }; + loadUserInfo(); + }, []); + + useEffect(() => { const loadData = async () => { try { const RSVPInfo = await loadAdmissionRSVP(); @@ -418,7 +449,6 @@ export default function Profile() { > {name} - {track} - + { + if (signOutPopupActive) { + sessionStorage.removeItem("token"); + webSignOutUser(); + } + if (userId) setSignOutPopupActive(true); + }} + sx={{ + bottom: "4px", + right: "40px", + fontSize: "12px", + color: "#7bff616b" + }} + > + {signOutPopupActive + ? "sign out?" + : (userId ?? "not signed in")} + SHOW QR + { + if (signOutPopupActive) { + sessionStorage.removeItem("token"); + webSignOutUser(); + } + if (userId) setSignOutPopupActive(true); + }} + sx={{ + bottom: "50px", + right: "10px", + fontSize: "12px", + color: "#7bff616b" + }} + > + {signOutPopupActive + ? "sign out?" + : (userId ?? "not signed in")} + ) : ( diff --git a/util/api.ts b/util/api.ts index 38e300b5..b2a3c7cf 100644 --- a/util/api.ts +++ b/util/api.ts @@ -10,7 +10,8 @@ import { RSVPInfo, EventType, MentorProfile, - JudgeProfile + JudgeProfile, + UserInfo } from "./types"; const APIv2 = "https://adonix.hackillinois.org"; @@ -206,6 +207,10 @@ export async function postAuthRefresh(): Promise { await requestv2("POST", "/auth/refresh", {}); } +export async function webSignOutUser(): Promise { + await requestv2("POST", "/auth/logout", {}); +} + export async function getEvents(): Promise { const res = await requestv2("GET", "/event").catch(handleError); return res.events as EventType[]; @@ -227,3 +232,8 @@ export async function getJudges(): Promise { const res = await requestv2("GET", "/judge/info/").catch(handleError); return res as JudgeProfile[]; } + +export async function getUserInfo(): Promise { + const res = await requestv2("GET", "/user").catch(handleError); + return res as UserInfo; +} diff --git a/util/types.ts b/util/types.ts index 90d1f329..d4c8c34b 100644 --- a/util/types.ts +++ b/util/types.ts @@ -229,3 +229,9 @@ export type JudgeProfile = { description: string; imageUrl: string; }; + +export type UserInfo = { + userId: string; + name: string; + email: string; +}; From 60a05eb27960866cc38fbe58eb697449abeb6175 Mon Sep 17 00:00:00 2001 From: seventhriver <129530873+seventhriver@users.noreply.github.com> Date: Fri, 27 Feb 2026 20:03:36 -0600 Subject: [PATCH 2/3] Reload page on signout --- app/profile/page.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/profile/page.tsx b/app/profile/page.tsx index 68907b5d..6306e452 100644 --- a/app/profile/page.tsx +++ b/app/profile/page.tsx @@ -525,7 +525,9 @@ export default function Profile() { onClick={() => { if (signOutPopupActive) { sessionStorage.removeItem("token"); - webSignOutUser(); + webSignOutUser().then(() => + window.location.reload() + ); } if (userId) setSignOutPopupActive(true); }} @@ -580,7 +582,9 @@ export default function Profile() { onClick={() => { if (signOutPopupActive) { sessionStorage.removeItem("token"); - webSignOutUser(); + webSignOutUser().then(() => + window.location.reload() + ); } if (userId) setSignOutPopupActive(true); }} From 3a401c5780505ad1bece9fc6390a52bfb4a13d9e Mon Sep 17 00:00:00 2001 From: seventhriver <129530873+seventhriver@users.noreply.github.com> Date: Fri, 27 Feb 2026 20:06:31 -0600 Subject: [PATCH 3/3] Fix conflict --- app/profile/page.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/profile/page.tsx b/app/profile/page.tsx index 6306e452..3fe2758e 100644 --- a/app/profile/page.tsx +++ b/app/profile/page.tsx @@ -84,13 +84,12 @@ export default function Profile() { fetchQRCode(); }; - const signOutUser = - // Auto-refresh QR code every 5 minutes while the dialog is open - useEffect(() => { - if (!showQR) return; - const interval = setInterval(fetchQRCode, 5 * 60 * 1000); - return () => clearInterval(interval); - }, [showQR, fetchQRCode]); + // Auto-refresh QR code every 5 minutes while the dialog is open + useEffect(() => { + if (!showQR) return; + const interval = setInterval(fetchQRCode, 5 * 60 * 1000); + return () => clearInterval(interval); + }, [showQR, fetchQRCode]); const confirmAvatarPicker = async () => { setLoading(true);