From 2638517bb373900fd0ab7b6409deb6c82fef3fd9 Mon Sep 17 00:00:00 2001 From: Julia Jeanne Dowejko Date: Mon, 6 Jul 2026 21:20:44 +0200 Subject: [PATCH] Fixes to Ban Appeal --- src/constants/appealStatus.ts | 7 ++ src/constants/banStatus.ts | 9 +++ src/pages/appeal.tsx | 127 ++++++++++++++++++++++++---------- 3 files changed, 107 insertions(+), 36 deletions(-) create mode 100644 src/constants/appealStatus.ts create mode 100644 src/constants/banStatus.ts diff --git a/src/constants/appealStatus.ts b/src/constants/appealStatus.ts new file mode 100644 index 0000000..085b14e --- /dev/null +++ b/src/constants/appealStatus.ts @@ -0,0 +1,7 @@ +enum AppealStatus { + Received = "RECEIVED", + Accepted = "ACCEPTED", + Denied = "DENIED", +} + +export default AppealStatus; diff --git a/src/constants/banStatus.ts b/src/constants/banStatus.ts new file mode 100644 index 0000000..1ee1524 --- /dev/null +++ b/src/constants/banStatus.ts @@ -0,0 +1,9 @@ +enum BanStatus { + Unknown = "unknown", + NotBanned = "not_banned", + CanAppeal = "can_appeal", + HasAppeal = "has_appeal", + CanReappeal = "can_reappeal", +} + +export default BanStatus; diff --git a/src/pages/appeal.tsx b/src/pages/appeal.tsx index 14d8bb3..a24d28a 100644 --- a/src/pages/appeal.tsx +++ b/src/pages/appeal.tsx @@ -5,9 +5,11 @@ import Header from "../components/Header"; import Footer from "../components/Footer"; import AppealForm from "../components/AppealForm"; import { getLoginUrl } from "../utils/keycloak"; +import BanStatus from "../constants/banStatus"; +import AppealStatus from "../constants/appealStatus"; interface Appeal { - status: string; + status: AppealStatus; created_at: string; decided_at?: string; reminded_at?: string; @@ -21,9 +23,7 @@ interface Appeal { const AppealPage: React.FC = () => { const [token, setToken] = useState(null); const [loading, setLoading] = useState(true); - const [banStatus, setBanStatus] = useState< - "unknown" | "can_appeal" | "has_appeal" | "not_banned" | "can_reappeal" - >("unknown"); + const [banStatus, setBanStatus] = useState(BanStatus.Unknown); const [latestAppeal, setLatestAppeal] = useState(null); const [submitting, setSubmitting] = useState(false); const [message, setMessage] = useState(null); @@ -47,7 +47,9 @@ const AppealPage: React.FC = () => { const savedToken = sessionStorage.getItem("kc_token"); const refreshToken = sessionStorage.getItem("kc_refresh_token"); - if (!savedToken) return null; + if (!savedToken) { + return null; + } try { const tokenData = JSON.parse(atob(savedToken.split(".")[1])); @@ -157,8 +159,13 @@ const AppealPage: React.FC = () => { } function canReappeal(appeal: Appeal | null): boolean { - if (!appeal || appeal.status !== "DENIED" || !appeal.decided_at) + if ( + !appeal || + appeal.status !== AppealStatus.Denied || + !appeal.decided_at + ) { return false; + } const decidedAt = new Date(appeal.decided_at); @@ -176,7 +183,9 @@ const AppealPage: React.FC = () => { } function canShowReminder(appeal: Appeal | null): boolean { - if (!appeal || appeal.status !== "RECEIVED") return false; + if (!appeal || appeal.status !== AppealStatus.Received) { + return false; + } const createdAt = new Date(appeal.created_at); @@ -208,7 +217,7 @@ const AppealPage: React.FC = () => { // Verify we have a token in sessionStorage before attempting API calls const savedToken = sessionStorage.getItem("kc_token"); if (!savedToken) { - setBanStatus("unknown"); + setBanStatus(BanStatus.Unknown); setLoading(false); return; } @@ -245,7 +254,7 @@ const AppealPage: React.FC = () => { } if (!currentBanStatus.banned) { - setBanStatus("not_banned"); + setBanStatus(BanStatus.NotBanned); setLoading(false); return; } @@ -253,28 +262,28 @@ const AppealPage: React.FC = () => { // User is banned - determine appeal status if (hasAppeal && appeal) { // Check if this appeal is for the current ban - if (appeal.status === "ACCEPTED") { + if (appeal.status === AppealStatus.Accepted) { // Previous appeal was accepted, they can make a new appeal for current ban - setBanStatus("can_appeal"); - } else if (appeal.status === "DENIED") { + setBanStatus(BanStatus.CanAppeal); + } else if (appeal.status === AppealStatus.Denied) { // Check if enough time has passed to reappeal if (canReappeal(appeal)) { - setBanStatus("can_reappeal"); // Show reappeal UI with previous appeal info + setBanStatus(BanStatus.CanReappeal); // Show reappeal UI with previous appeal info } else { - setBanStatus("has_appeal"); // Show denial message and waiting period + setBanStatus(BanStatus.HasAppeal); // Show denial message and waiting period } } else { // Appeal is still pending (RECEIVED status) - setBanStatus("has_appeal"); + setBanStatus(BanStatus.HasAppeal); } } else if (!hasAppeal) { // No appeal found - user can create one - setBanStatus("can_appeal"); + setBanStatus(BanStatus.CanAppeal); } else { - setBanStatus("unknown"); + setBanStatus(BanStatus.Unknown); } } catch { - setBanStatus("unknown"); + setBanStatus(BanStatus.Unknown); } finally { setLoading(false); isCheckingBanRef.current = false; @@ -300,7 +309,7 @@ const AppealPage: React.FC = () => { if (res.ok) { const successData = await res.json(); setMessage(successData.message || "Your appeal has been submitted."); - setBanStatus("has_appeal"); + setBanStatus(BanStatus.HasAppeal); // Refresh to get the new appeal checkBan(); setTimeout(() => setMessage(null), 3000); @@ -360,14 +369,14 @@ const AppealPage: React.FC = () => { } } - const getStatusBadge = (status?: string) => { + const getStatusBadge = (status?: AppealStatus) => { const s = status ?? "Unknown"; switch (s) { - case "ACCEPTED": + case AppealStatus.Accepted: return Accepted; - case "DENIED": + case AppealStatus.Denied: return Denied; - case "RECEIVED": + case AppealStatus.Received: return ( Under Review ); @@ -557,7 +566,7 @@ const AppealPage: React.FC = () => { )} - {token && banStatus === "can_appeal" && ( + {token && banStatus === BanStatus.CanAppeal && (
@@ -577,7 +586,7 @@ const AppealPage: React.FC = () => {
)} - {token && banStatus === "can_reappeal" && ( + {token && banStatus === BanStatus.CanReappeal && (
@@ -648,7 +657,7 @@ const AppealPage: React.FC = () => {
)} - {token && banStatus === "has_appeal" && ( + {token && banStatus === BanStatus.HasAppeal && (
@@ -666,7 +675,9 @@ const AppealPage: React.FC = () => {

Status:{" "} - {getStatusBadge(latestAppeal?.status || "RECEIVED")} + {getStatusBadge( + latestAppeal?.status || AppealStatus.Received, + )}

@@ -679,7 +690,7 @@ const AppealPage: React.FC = () => {

- {latestAppeal?.status === "RECEIVED" && ( + {latestAppeal?.status === AppealStatus.Received && (

Reminder available:{" "} @@ -719,7 +730,7 @@ const AppealPage: React.FC = () => { )}

- {latestAppeal?.status === "RECEIVED" && + {latestAppeal?.status === AppealStatus.Received && (() => { const canRemind = canShowReminder(latestAppeal); const buttonClass = `btn ${canRemind ? "btn-outline-primary" : "btn-outline-secondary"}`; @@ -835,7 +846,7 @@ const AppealPage: React.FC = () => {
)} - {latestAppeal?.status === "RECEIVED" && + {latestAppeal?.status === AppealStatus.Received && !canShowReminder(latestAppeal) && !latestAppeal?.reminded_at && (
@@ -856,7 +867,7 @@ const AppealPage: React.FC = () => {
- {latestAppeal?.status === "ACCEPTED" && ( + {latestAppeal?.status === AppealStatus.Accepted && (
@@ -887,7 +898,7 @@ const AppealPage: React.FC = () => {
)} - {latestAppeal?.status === "DENIED" && ( + {latestAppeal?.status === AppealStatus.Denied && (
@@ -920,7 +931,7 @@ const AppealPage: React.FC = () => {
)} - {token && banStatus === "not_banned" && ( + {token && banStatus === BanStatus.NotBanned && (
@@ -947,7 +958,7 @@ const AppealPage: React.FC = () => { {getStatusBadge(latestAppeal.status)}

- {latestAppeal.status === "ACCEPTED" && ( + {latestAppeal.status === AppealStatus.Accepted && (
@@ -973,7 +984,7 @@ const AppealPage: React.FC = () => {
)} - {latestAppeal.status === "DENIED" && ( + {latestAppeal.status === AppealStatus.Denied && (
@@ -996,7 +1007,7 @@ const AppealPage: React.FC = () => {
)} - {latestAppeal.status === "RECEIVED" && ( + {latestAppeal.status === AppealStatus.Received && (
Appeal Still @@ -1040,6 +1051,50 @@ const AppealPage: React.FC = () => {
)} + {token && banStatus === BanStatus.Unknown && ( +
+
+
+
+
+

Ban Appeal

+
+ +
+
+
+ +
+
+ We couldn't load your appeal status +
+

+ Something went wrong while checking your ban and appeal + status. This can happen if the service is temporarily + unavailable. Please try again in a moment. +

+ +
+
+
+
+
+
+ )} + {message && (