diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 794e994..a6f0126 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,10 +1,17 @@ import Image from "next/image"; import { Tooltip } from "@mui/material"; +import { useState } from "react"; import logo from "../../public/assets/img/logo.png"; import ProfileButton from "./ProfileButton"; function Header() { const domain = process.env.NEXT_PUBLIC_DNS_DOMAIN || "tripsit.me"; + const [mobileMenuOpen, setMobileMenuOpen] = useState(false); + + const toggleMobileMenu = () => { + setMobileMenuOpen(!mobileMenuOpen); + }; + return ( ); } diff --git a/src/pages/appeal.tsx b/src/pages/appeal.tsx index 62e6992..afe725b 100644 --- a/src/pages/appeal.tsx +++ b/src/pages/appeal.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useState, useRef } from "react"; +import Head from "next/head"; import { Button } from "@nextui-org/react"; import Header from "../components/Header"; import Footer from "../components/Footer"; @@ -34,6 +35,8 @@ const AppealPage: React.FC = () => { // Use ref to prevent concurrent token refreshes const isRefreshingRef = useRef(false); const refreshPromiseRef = useRef | null>(null); + // Use ref to prevent concurrent checkBan calls + const isCheckingBanRef = useRef(false); async function refreshTokenIfNeeded() { // If already refreshing, wait for that promise to complete @@ -143,6 +146,7 @@ const AppealPage: React.FC = () => { window.dispatchEvent(new Event("tokensUpdated")); // Clean up the URL by removing the query parameters + document.title = "Ban Appeal - TripSit"; window.history.replaceState({}, "", window.location.pathname); } } catch { @@ -190,7 +194,17 @@ const AppealPage: React.FC = () => { } async function checkBan() { + // Prevent concurrent executions + if (isCheckingBanRef.current) { + return; + } + + isCheckingBanRef.current = true; + try { + // Reset appeal state at start to prevent stale data + setLatestAppeal(null); + // Verify we have a token in sessionStorage before attempting API calls const savedToken = sessionStorage.getItem("kc_token"); if (!savedToken) { @@ -263,6 +277,7 @@ const AppealPage: React.FC = () => { setBanStatus("unknown"); } finally { setLoading(false); + isCheckingBanRef.current = false; } } @@ -370,6 +385,7 @@ const AppealPage: React.FC = () => { setToken(validToken); // Clean up any lingering auth query params from URL if (window.location.search) { + document.title = "Ban Appeal - TripSit"; window.history.replaceState({}, "", window.location.pathname); } } else { @@ -401,14 +417,17 @@ const AppealPage: React.FC = () => { // Set up new interval to refresh every 30 seconds refreshIntervalRef.current = setInterval(async () => { const refreshedToken = await refreshTokenIfNeeded(); + // Only update token state if it actually changed to prevent unnecessary re-renders if (refreshedToken && refreshedToken !== token) { setToken(refreshedToken); - } else if (!refreshedToken) { + } else if (!refreshedToken && token) { + // Token is now invalid, clear it setToken(null); if (refreshIntervalRef.current) { clearInterval(refreshIntervalRef.current); } } + // If refreshedToken === token, do nothing (no state change needed) }, 30000); // 30 seconds } @@ -433,6 +452,9 @@ const AppealPage: React.FC = () => { if (loading) { return ( <> + + Ban Appeal - TripSit +
{ return ( <> + + Ban Appeal - TripSit +
{!token && (