From 690adf5a8629ceff824a45e1fb93568e4b3f216b Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 19:05:06 -0700
Subject: [PATCH 01/15] ai lol

---
 .../[submissionId]/_reviewButtons.tsx         | 89 ++++++++++++++++---
 1 file changed, 75 insertions(+), 14 deletions(-)

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index 822327c..703dab4 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -45,7 +45,6 @@ function ReviewButton(props: ReviewButton) {
 }
 
 export default function ReviewButtons(props: ReviewId) {
-	const submissionId = props.submissionId
 	// When is each button visible?
 	// Multiple buttons can be visible at once.
 	// Action         | Role      | When Current Status is One of:
@@ -59,16 +58,78 @@ export default function ReviewButtons(props: ReviewId) {
 	// RequestChanges | Reviewer  | Validated, Accepted, Submitted
 	// Upload         | MapAdmin  | Validated
 	// ResetUploading | MapAdmin  | Uploading
-	return (
-		<section className="review-set">
-			<ReviewButton color="info"  name="Submit"    action="submit"           submissionId={submissionId}/>
-			<ReviewButton color="info"  name="Revoke"    action="revoke"           submissionId={submissionId}/>
-			<ReviewButton color="info"  name="Accept"    action="trigger-validate" submissionId={submissionId}/>
-			<ReviewButton color="info"  name="Validate"  action="retry-validate"   submissionId={submissionId}/>
-			<ReviewButton color="error" name="Reject"    action="reject"           submissionId={submissionId}/>
-			<ReviewButton color="info"  name="Upload"    action="trigger-upload"   submissionId={submissionId}/>
-			<ReviewButton color="error" name="Reset Uploading (fix softlocked status)"    action="reset-uploading"   submissionId={submissionId}/>
-			<ReviewButton color="error" name="Reset Validating (fix softlocked status)"   action="reset-validating"  submissionId={submissionId}/>
-		</section>
-	)
-}
+  const { submissionId } = props;
+  const [roles, setRoles] = useState<string[]>([]);
+  const [status, setStatus] = useState<string | null>(null);
+  const [loading, setLoading] = useState(true);
+
+  useEffect(() => {
+    async function fetchData() {
+      try {
+        // Fetch user roles
+        const rolesResponse = await fetch("/api/session/roles");
+        const rolesData = await rolesResponse.json();
+
+        // Fetch submission status
+        const statusResponse = await fetch(
+          `/api/submissions/${submissionId}/status`
+        );
+        const statusData = await statusResponse.json();
+
+        setRoles(rolesData);
+        setStatus(statusData.status);
+      } catch (error) {
+        console.error("Error fetching data:", error);
+      } finally {
+        setLoading(false);
+      }
+    }
+
+    fetchData();
+  }, [submissionId]);
+
+  if (loading) return <p>Loading...</p>;
+
+  const visibleButtons: ReviewButtonProps[] = [];
+
+  if (roles.includes("Submitter")) {
+    if (["UnderConstruction", "ChangesRequested"].includes(status!)) {
+      visibleButtons.push({ name: "Submit", action: "submit", color: "info", submissionId });
+    }
+    if (["Submitted", "ChangesRequested"].includes(status!)) {
+      visibleButtons.push({ name: "Revoke", action: "revoke", color: "info", submissionId });
+    }
+  }
+
+  if (roles.includes("Reviewer")) {
+    if (status === "Submitted") {
+      visibleButtons.push({ name: "Accept", action: "trigger-validate", color: "info", submissionId });
+      visibleButtons.push({ name: "Reject", action: "reject", color: "error", submissionId });
+    }
+    if (status === "Accepted") {
+      visibleButtons.push({ name: "Validate", action: "retry-validate", color: "info", submissionId });
+    }
+    if (status === "Validating") {
+      visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", submissionId });
+    }
+    if (["Validated", "Accepted", "Submitted"].includes(status!)) {
+      visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", submissionId });
+    }
+  }
+
+  if (roles.includes("MapAdmin")) {
+    if (status === "Validated") {
+      visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", submissionId });
+    }
+    if (status === "Uploading") {
+      visibleButtons.push({ name: "Reset Uploading (fix softlocked status)", action: "reset-uploading", color: "error", submissionId });
+    }
+  }
+
+  return (
+    <section className="review-set">
+      {visibleButtons.map((btn) => (
+        <ReviewButton key={btn.action} {...btn} />
+      ))}
+    </section>
+  );
-- 
2.47.1


From 98ac17d4786a7dbd9cf1dcaac09a4da270a0f2f4 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 20:17:48 -0700
Subject: [PATCH 02/15] neat

---
 .../[submissionId]/_reviewButtons.tsx         | 136 +++++++++---------
 1 file changed, 69 insertions(+), 67 deletions(-)

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index 703dab4..e3cc4b9 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -1,8 +1,9 @@
 import { Button, ButtonOwnProps } from "@mui/material";
+import { useState, useEffect } from "react";
 
 type Actions    = "Completed" | "Submit" | "Reject" | "Revoke"
-type ApiActions = Lowercase<Actions> | "trigger-validate" | "retry-validate" | "trigger-upload" | "reset-uploading" | "reset-validating"
-type Review     = Actions | "Accept" | "Validate" | "Upload" | "Reset Uploading (fix softlocked status)" | "Reset Validating (fix softlocked status)" | "Request Changes"
+type ApiActions = Lowercase<Actions> | "request-changes" | "trigger-validate" | "retry-validate" | "trigger-upload" | "reset-uploading" | "reset-validating"
+type Review     = Actions | "Request Changes" | "Accept" | "Validate" | "Upload" | "Reset Uploading (fix softlocked status)" | "Reset Validating (fix softlocked status)" | "Request Changes"
 
 interface ReviewButton {
 	name: Review,
@@ -58,78 +59,79 @@ export default function ReviewButtons(props: ReviewId) {
 	// RequestChanges | Reviewer  | Validated, Accepted, Submitted
 	// Upload         | MapAdmin  | Validated
 	// ResetUploading | MapAdmin  | Uploading
-  const { submissionId } = props;
-  const [roles, setRoles] = useState<string[]>([]);
-  const [status, setStatus] = useState<string | null>(null);
-  const [loading, setLoading] = useState(true);
+	const { submissionId } = props;
+	const [roles, setRoles] = useState<string[]>([]);
+	const [status, setStatus] = useState<string | null>(null);
+	const [loading, setLoading] = useState(true);
 
-  useEffect(() => {
-    async function fetchData() {
-      try {
-        // Fetch user roles
-        const rolesResponse = await fetch("/api/session/roles");
-        const rolesData = await rolesResponse.json();
+	useEffect(() => {
+		async function fetchData() {
+			try {
+				// Fetch user roles
+				const rolesResponse = await fetch("/api/session/roles");
+				const rolesData = await rolesResponse.json();
 
-        // Fetch submission status
-        const statusResponse = await fetch(
-          `/api/submissions/${submissionId}/status`
-        );
-        const statusData = await statusResponse.json();
+				// Fetch submission status
+				const statusResponse = await fetch(
+					`/api/submissions/${submissionId}/status`
+				);
+				const statusData = await statusResponse.json();
 
-        setRoles(rolesData);
-        setStatus(statusData.status);
-      } catch (error) {
-        console.error("Error fetching data:", error);
-      } finally {
-        setLoading(false);
-      }
-    }
+				setRoles(rolesData);
+				setStatus(statusData.status);
+			} catch (error) {
+				console.error("Error fetching data:", error);
+			} finally {
+				setLoading(false);
+			}
+		}
 
-    fetchData();
-  }, [submissionId]);
+		fetchData();
+	}, [submissionId]);
 
-  if (loading) return <p>Loading...</p>;
+	if (loading) return <p>Loading...</p>;
 
-  const visibleButtons: ReviewButtonProps[] = [];
+	const visibleButtons: ReviewButton[] = [];
 
-  if (roles.includes("Submitter")) {
-    if (["UnderConstruction", "ChangesRequested"].includes(status!)) {
-      visibleButtons.push({ name: "Submit", action: "submit", color: "info", submissionId });
-    }
-    if (["Submitted", "ChangesRequested"].includes(status!)) {
-      visibleButtons.push({ name: "Revoke", action: "revoke", color: "info", submissionId });
-    }
-  }
+	if (roles.includes("Submitter")) {
+		if (["UnderConstruction", "ChangesRequested"].includes(status!)) {
+			visibleButtons.push({ name: "Submit", action: "submit", color: "info", submissionId });
+		}
+		if (["Submitted", "ChangesRequested"].includes(status!)) {
+			visibleButtons.push({ name: "Revoke", action: "revoke", color: "info", submissionId });
+		}
+	}
 
-  if (roles.includes("Reviewer")) {
-    if (status === "Submitted") {
-      visibleButtons.push({ name: "Accept", action: "trigger-validate", color: "info", submissionId });
-      visibleButtons.push({ name: "Reject", action: "reject", color: "error", submissionId });
-    }
-    if (status === "Accepted") {
-      visibleButtons.push({ name: "Validate", action: "retry-validate", color: "info", submissionId });
-    }
-    if (status === "Validating") {
-      visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", submissionId });
-    }
-    if (["Validated", "Accepted", "Submitted"].includes(status!)) {
-      visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", submissionId });
-    }
-  }
+	if (roles.includes("Reviewer")) {
+		if (status === "Submitted") {
+			visibleButtons.push({ name: "Accept", action: "trigger-validate", color: "info", submissionId });
+			visibleButtons.push({ name: "Reject", action: "reject", color: "error", submissionId });
+		}
+		if (status === "Accepted") {
+			visibleButtons.push({ name: "Validate", action: "retry-validate", color: "info", submissionId });
+		}
+		if (status === "Validating") {
+			visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", submissionId });
+		}
+		if (["Validated", "Accepted", "Submitted"].includes(status!)) {
+			visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", submissionId });
+		}
+	}
 
-  if (roles.includes("MapAdmin")) {
-    if (status === "Validated") {
-      visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", submissionId });
-    }
-    if (status === "Uploading") {
-      visibleButtons.push({ name: "Reset Uploading (fix softlocked status)", action: "reset-uploading", color: "error", submissionId });
-    }
-  }
+	if (roles.includes("MapAdmin")) {
+		if (status === "Validated") {
+			visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", submissionId });
+		}
+		if (status === "Uploading") {
+			visibleButtons.push({ name: "Reset Uploading (fix softlocked status)", action: "reset-uploading", color: "error", submissionId });
+		}
+	}
 
-  return (
-    <section className="review-set">
-      {visibleButtons.map((btn) => (
-        <ReviewButton key={btn.action} {...btn} />
-      ))}
-    </section>
-  );
+	return (
+		<section className="review-set">
+			{visibleButtons.map((btn) => (
+				<ReviewButton key={btn.action} {...btn} />
+			))}
+		</section>
+	);
+}
-- 
2.47.1


From 0955fbd88e9d7aea3b8063594e6ff2b9dec230ba Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 20:33:45 -0700
Subject: [PATCH 03/15] me + ai = javascript

---
 .../[submissionId]/_reviewButtons.tsx         | 29 ++++++++++---------
 web/src/app/ts/Roles.ts                       | 15 ++++++++++
 2 files changed, 31 insertions(+), 13 deletions(-)
 create mode 100644 web/src/app/ts/Roles.ts

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index e3cc4b9..5a10850 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -1,3 +1,5 @@
+import { Roles } from "@/app/ts/Roles";
+import { SubmissionStatus } from "@/app/ts/Submission";
 import { Button, ButtonOwnProps } from "@mui/material";
 import { useState, useEffect } from "react";
 
@@ -60,8 +62,8 @@ export default function ReviewButtons(props: ReviewId) {
 	// Upload         | MapAdmin  | Validated
 	// ResetUploading | MapAdmin  | Uploading
 	const { submissionId } = props;
-	const [roles, setRoles] = useState<string[]>([]);
-	const [status, setStatus] = useState<string | null>(null);
+	const [roles, setRoles] = useState<Roles>(Roles.Empty);
+	const [status, setStatus] = useState<SubmissionStatus>(SubmissionStatus.UnderConstruction);
 	const [loading, setLoading] = useState(true);
 
 	useEffect(() => {
@@ -93,36 +95,37 @@ export default function ReviewButtons(props: ReviewId) {
 
 	const visibleButtons: ReviewButton[] = [];
 
-	if (roles.includes("Submitter")) {
-		if (["UnderConstruction", "ChangesRequested"].includes(status!)) {
+	const is_submitter = false; // TODO: MY_USER === submission.Submitter
+	if (is_submitter) {
+		if ([SubmissionStatus.UnderConstruction, SubmissionStatus.ChangesRequested].includes(status!)) {
 			visibleButtons.push({ name: "Submit", action: "submit", color: "info", submissionId });
 		}
-		if (["Submitted", "ChangesRequested"].includes(status!)) {
+		if ([SubmissionStatus.Submitted, SubmissionStatus.ChangesRequested].includes(status!)) {
 			visibleButtons.push({ name: "Revoke", action: "revoke", color: "info", submissionId });
 		}
 	}
 
-	if (roles.includes("Reviewer")) {
-		if (status === "Submitted") {
+	if (roles&Roles.SubmissionReview) {
+		if (status === SubmissionStatus.Submitted) {
 			visibleButtons.push({ name: "Accept", action: "trigger-validate", color: "info", submissionId });
 			visibleButtons.push({ name: "Reject", action: "reject", color: "error", submissionId });
 		}
-		if (status === "Accepted") {
+		if (status === SubmissionStatus.Accepted) {
 			visibleButtons.push({ name: "Validate", action: "retry-validate", color: "info", submissionId });
 		}
-		if (status === "Validating") {
+		if (status === SubmissionStatus.Validating) {
 			visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", submissionId });
 		}
-		if (["Validated", "Accepted", "Submitted"].includes(status!)) {
+		if ([SubmissionStatus.Validated, SubmissionStatus.Accepted, SubmissionStatus.Submitted].includes(status!)) {
 			visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", submissionId });
 		}
 	}
 
-	if (roles.includes("MapAdmin")) {
-		if (status === "Validated") {
+	if (roles&Roles.SubmissionUpload) {
+		if (status === SubmissionStatus.Validated) {
 			visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", submissionId });
 		}
-		if (status === "Uploading") {
+		if (status === SubmissionStatus.Uploading) {
 			visibleButtons.push({ name: "Reset Uploading (fix softlocked status)", action: "reset-uploading", color: "error", submissionId });
 		}
 	}
diff --git a/web/src/app/ts/Roles.ts b/web/src/app/ts/Roles.ts
new file mode 100644
index 0000000..af94e36
--- /dev/null
+++ b/web/src/app/ts/Roles.ts
@@ -0,0 +1,15 @@
+// Submissions roles bitflag
+enum Roles {
+  SubmissionUpload = 1 << 6,
+  SubmissionReview = 1 << 5,
+  SubmissionRelease = 1 << 4,
+  ScriptWrite = 1 << 3,
+  MapfixUpload = 1 << 2,
+  MapfixReview = 1 << 1,
+  MapDownload = 1 << 0,
+  Empty = 0
+}
+
+export {
+	Roles,
+}
-- 
2.47.1


From 1e880cb95c55cc5eb47e2a90cad89d5da36c1e90 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 20:39:02 -0700
Subject: [PATCH 04/15] parse int

---
 web/src/app/submissions/[submissionId]/_reviewButtons.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index 5a10850..5b1cdbe 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -71,7 +71,7 @@ export default function ReviewButtons(props: ReviewId) {
 			try {
 				// Fetch user roles
 				const rolesResponse = await fetch("/api/session/roles");
-				const rolesData = await rolesResponse.json();
+				const rolesData = parseInt(await rolesResponse.text());
 
 				// Fetch submission status
 				const statusResponse = await fetch(
-- 
2.47.1


From 5e8fd0744ca5b2bcad1b5fc4250f8c6a6bfe685f Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 20:49:41 -0700
Subject: [PATCH 05/15] plumb status

---
 .../[submissionId]/_reviewButtons.tsx         | 29 +++++++------------
 .../app/submissions/[submissionId]/page.tsx   |  5 ++--
 2 files changed, 14 insertions(+), 20 deletions(-)

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index 5b1cdbe..71fb83e 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -15,7 +15,8 @@ interface ReviewButton {
 }
 
 interface ReviewId {
-	submissionId: string
+	submissionId: string,
+	submissionStatus: number,
 }
 
 async function ReviewButtonClicked(action: ApiActions, submissionId: string) {
@@ -61,9 +62,8 @@ export default function ReviewButtons(props: ReviewId) {
 	// RequestChanges | Reviewer  | Validated, Accepted, Submitted
 	// Upload         | MapAdmin  | Validated
 	// ResetUploading | MapAdmin  | Uploading
-	const { submissionId } = props;
+	const { submissionId, submissionStatus } = props;
 	const [roles, setRoles] = useState<Roles>(Roles.Empty);
-	const [status, setStatus] = useState<SubmissionStatus>(SubmissionStatus.UnderConstruction);
 	const [loading, setLoading] = useState(true);
 
 	useEffect(() => {
@@ -73,14 +73,7 @@ export default function ReviewButtons(props: ReviewId) {
 				const rolesResponse = await fetch("/api/session/roles");
 				const rolesData = parseInt(await rolesResponse.text());
 
-				// Fetch submission status
-				const statusResponse = await fetch(
-					`/api/submissions/${submissionId}/status`
-				);
-				const statusData = await statusResponse.json();
-
 				setRoles(rolesData);
-				setStatus(statusData.status);
 			} catch (error) {
 				console.error("Error fetching data:", error);
 			} finally {
@@ -97,35 +90,35 @@ export default function ReviewButtons(props: ReviewId) {
 
 	const is_submitter = false; // TODO: MY_USER === submission.Submitter
 	if (is_submitter) {
-		if ([SubmissionStatus.UnderConstruction, SubmissionStatus.ChangesRequested].includes(status!)) {
+		if ([SubmissionStatus.UnderConstruction, SubmissionStatus.ChangesRequested].includes(submissionStatus!)) {
 			visibleButtons.push({ name: "Submit", action: "submit", color: "info", submissionId });
 		}
-		if ([SubmissionStatus.Submitted, SubmissionStatus.ChangesRequested].includes(status!)) {
+		if ([SubmissionStatus.Submitted, SubmissionStatus.ChangesRequested].includes(submissionStatus!)) {
 			visibleButtons.push({ name: "Revoke", action: "revoke", color: "info", submissionId });
 		}
 	}
 
 	if (roles&Roles.SubmissionReview) {
-		if (status === SubmissionStatus.Submitted) {
+		if (submissionStatus === SubmissionStatus.Submitted) {
 			visibleButtons.push({ name: "Accept", action: "trigger-validate", color: "info", submissionId });
 			visibleButtons.push({ name: "Reject", action: "reject", color: "error", submissionId });
 		}
-		if (status === SubmissionStatus.Accepted) {
+		if (submissionStatus === SubmissionStatus.Accepted) {
 			visibleButtons.push({ name: "Validate", action: "retry-validate", color: "info", submissionId });
 		}
-		if (status === SubmissionStatus.Validating) {
+		if (submissionStatus === SubmissionStatus.Validating) {
 			visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", submissionId });
 		}
-		if ([SubmissionStatus.Validated, SubmissionStatus.Accepted, SubmissionStatus.Submitted].includes(status!)) {
+		if ([SubmissionStatus.Validated, SubmissionStatus.Accepted, SubmissionStatus.Submitted].includes(submissionStatus!)) {
 			visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", submissionId });
 		}
 	}
 
 	if (roles&Roles.SubmissionUpload) {
-		if (status === SubmissionStatus.Validated) {
+		if (submissionStatus === SubmissionStatus.Validated) {
 			visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", submissionId });
 		}
-		if (status === SubmissionStatus.Uploading) {
+		if (submissionStatus === SubmissionStatus.Uploading) {
 			visibleButtons.push({ name: "Reset Uploading (fix softlocked status)", action: "reset-uploading", color: "error", submissionId });
 		}
 	}
diff --git a/web/src/app/submissions/[submissionId]/page.tsx b/web/src/app/submissions/[submissionId]/page.tsx
index c78ba8b..3440604 100644
--- a/web/src/app/submissions/[submissionId]/page.tsx
+++ b/web/src/app/submissions/[submissionId]/page.tsx
@@ -17,6 +17,7 @@ import "./(styles)/page.scss";
 interface ReviewId {
 	submissionId: string;
 	assetId: number;
+	submissionStatus: number;
 }
 
 function Ratings() {
@@ -47,7 +48,7 @@ function RatingArea(submission: ReviewId) {
          		<MapImage id={submission.assetId}/>
          	</section>
             <Ratings/>
-			<ReviewButtons submissionId={submission.submissionId}/>
+			<ReviewButtons submissionId={submission.submissionId} submissionStatus={submission.submissionStatus}/>
         </aside>
     )
 }
@@ -97,7 +98,7 @@ export default function SubmissionInfoPage() {
         <Webpage>
             <main className="map-page-main">
                 <section className="review-section">
-					<RatingArea assetId={submission.AssetID} submissionId={dynamicId.submissionId}/>
+					<RatingArea assetId={submission.AssetID} submissionId={dynamicId.submissionId} submissionStatus={submission.StatusID}/>
                     <TitleAndComments name={submission.DisplayName} creator={submission.Creator} review={submission.StatusID} status_message={submission.StatusMessage} asset_id={submission.AssetID} comments={[]}/>
                 </section>
             </main>
-- 
2.47.1


From c253874ce36330aae3ce6b0930fb5a7dccb926b7 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 20:54:51 -0700
Subject: [PATCH 06/15] grab user + plumb submitter

---
 .../app/submissions/[submissionId]/_reviewButtons.tsx    | 9 +++++++--
 web/src/app/submissions/[submissionId]/page.tsx          | 5 +++--
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index 71fb83e..73e1581 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -17,6 +17,7 @@ interface ReviewButton {
 interface ReviewId {
 	submissionId: string,
 	submissionStatus: number,
+	submissionSubmitter: number,
 }
 
 async function ReviewButtonClicked(action: ApiActions, submissionId: string) {
@@ -63,6 +64,7 @@ export default function ReviewButtons(props: ReviewId) {
 	// Upload         | MapAdmin  | Validated
 	// ResetUploading | MapAdmin  | Uploading
 	const { submissionId, submissionStatus } = props;
+	const [user, setUser] = useState<number|null>(null);
 	const [roles, setRoles] = useState<Roles>(Roles.Empty);
 	const [loading, setLoading] = useState(true);
 
@@ -72,8 +74,12 @@ export default function ReviewButtons(props: ReviewId) {
 				// Fetch user roles
 				const rolesResponse = await fetch("/api/session/roles");
 				const rolesData = parseInt(await rolesResponse.text());
+				// Fetch user roles
+				const userResponse = await fetch("/api/session/user");
+				const userData = await userResponse.json();
 
 				setRoles(rolesData);
+				setUser(userData.userId);
 			} catch (error) {
 				console.error("Error fetching data:", error);
 			} finally {
@@ -88,8 +94,7 @@ export default function ReviewButtons(props: ReviewId) {
 
 	const visibleButtons: ReviewButton[] = [];
 
-	const is_submitter = false; // TODO: MY_USER === submission.Submitter
-	if (is_submitter) {
+	if (user === props.submissionSubmitter) {
 		if ([SubmissionStatus.UnderConstruction, SubmissionStatus.ChangesRequested].includes(submissionStatus!)) {
 			visibleButtons.push({ name: "Submit", action: "submit", color: "info", submissionId });
 		}
diff --git a/web/src/app/submissions/[submissionId]/page.tsx b/web/src/app/submissions/[submissionId]/page.tsx
index 3440604..9b8d4d1 100644
--- a/web/src/app/submissions/[submissionId]/page.tsx
+++ b/web/src/app/submissions/[submissionId]/page.tsx
@@ -18,6 +18,7 @@ interface ReviewId {
 	submissionId: string;
 	assetId: number;
 	submissionStatus: number;
+	submissionSubmitter: number,
 }
 
 function Ratings() {
@@ -48,7 +49,7 @@ function RatingArea(submission: ReviewId) {
          		<MapImage id={submission.assetId}/>
          	</section>
             <Ratings/>
-			<ReviewButtons submissionId={submission.submissionId} submissionStatus={submission.submissionStatus}/>
+			<ReviewButtons submissionId={submission.submissionId} submissionStatus={submission.submissionStatus} submissionSubmitter={submission.submissionSubmitter}/>
         </aside>
     )
 }
@@ -98,7 +99,7 @@ export default function SubmissionInfoPage() {
         <Webpage>
             <main className="map-page-main">
                 <section className="review-section">
-					<RatingArea assetId={submission.AssetID} submissionId={dynamicId.submissionId} submissionStatus={submission.StatusID}/>
+					<RatingArea assetId={submission.AssetID} submissionId={dynamicId.submissionId} submissionStatus={submission.StatusID} submissionSubmitter={submission.Submitter}/>
                     <TitleAndComments name={submission.DisplayName} creator={submission.Creator} review={submission.StatusID} status_message={submission.StatusMessage} asset_id={submission.AssetID} comments={[]}/>
                 </section>
             </main>
-- 
2.47.1


From 1b87f0a396170d2a7fb52794fe30a2722254cfbe Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 20:58:17 -0700
Subject: [PATCH 07/15] gotta go fast

---
 .../app/submissions/[submissionId]/_reviewButtons.tsx  | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index 73e1581..b156a73 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -71,12 +71,10 @@ export default function ReviewButtons(props: ReviewId) {
 	useEffect(() => {
 		async function fetchData() {
 			try {
-				// Fetch user roles
-				const rolesResponse = await fetch("/api/session/roles");
-				const rolesData = parseInt(await rolesResponse.text());
-				// Fetch user roles
-				const userResponse = await fetch("/api/session/user");
-				const userData = await userResponse.json();
+				const [rolesData, userData] = await Promise.all([
+					fetch("/api/session/roles").then(rolesResponse => rolesResponse.text()).then(text => parseInt(text, 10)),
+					fetch("/api/session/user").then(userResponse => userResponse.json())
+				]);
 
 				setRoles(rolesData);
 				setUser(userData.userId);
-- 
2.47.1


From 73a3ac61bd68ab20e1959a701b9a89c104e32724 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 21:07:15 -0700
Subject: [PATCH 08/15] comment mapfix vs submission status

---
 web/src/app/ts/Mapfix.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/web/src/app/ts/Mapfix.ts b/web/src/app/ts/Mapfix.ts
index 0a5bd25..0570db0 100644
--- a/web/src/app/ts/Mapfix.ts
+++ b/web/src/app/ts/Mapfix.ts
@@ -8,6 +8,7 @@ const enum MapfixStatus {
 	Uploading         = 6,
 	Uploaded          = 7,
 	Rejected          = 8,
+	// MapfixStatus does not have a Released state
 }
 
 interface MapfixInfo {
-- 
2.47.1


From 13651df94d9f2913c1425bbb17bf1b46d001e762 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 3 Apr 2025 21:17:18 -0700
Subject: [PATCH 09/15] case sensitive?

---
 web/src/app/submissions/[submissionId]/_reviewButtons.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index b156a73..a25a0f5 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -77,7 +77,7 @@ export default function ReviewButtons(props: ReviewId) {
 				]);
 
 				setRoles(rolesData);
-				setUser(userData.userId);
+				setUser(userData.UserID);
 			} catch (error) {
 				console.error("Error fetching data:", error);
 			} finally {
-- 
2.47.1


From b62b2fcf7bd6c5ba3ed5878d175468c7bcaf1504 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Fri, 4 Apr 2025 14:29:27 -0700
Subject: [PATCH 10/15] roles is not an enum

---
 .../[submissionId]/_reviewButtons.tsx         |  8 ++---
 web/src/app/ts/Roles.ts                       | 34 ++++++++++++-------
 2 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index a25a0f5..d721b2e 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -1,4 +1,4 @@
-import { Roles } from "@/app/ts/Roles";
+import { Roles, RolesConstants } from "@/app/ts/Roles";
 import { SubmissionStatus } from "@/app/ts/Submission";
 import { Button, ButtonOwnProps } from "@mui/material";
 import { useState, useEffect } from "react";
@@ -65,7 +65,7 @@ export default function ReviewButtons(props: ReviewId) {
 	// ResetUploading | MapAdmin  | Uploading
 	const { submissionId, submissionStatus } = props;
 	const [user, setUser] = useState<number|null>(null);
-	const [roles, setRoles] = useState<Roles>(Roles.Empty);
+	const [roles, setRoles] = useState<Roles>(RolesConstants.Empty);
 	const [loading, setLoading] = useState(true);
 
 	useEffect(() => {
@@ -101,7 +101,7 @@ export default function ReviewButtons(props: ReviewId) {
 		}
 	}
 
-	if (roles&Roles.SubmissionReview) {
+	if (roles&RolesConstants.SubmissionReview) {
 		if (submissionStatus === SubmissionStatus.Submitted) {
 			visibleButtons.push({ name: "Accept", action: "trigger-validate", color: "info", submissionId });
 			visibleButtons.push({ name: "Reject", action: "reject", color: "error", submissionId });
@@ -117,7 +117,7 @@ export default function ReviewButtons(props: ReviewId) {
 		}
 	}
 
-	if (roles&Roles.SubmissionUpload) {
+	if (roles&RolesConstants.SubmissionUpload) {
 		if (submissionStatus === SubmissionStatus.Validated) {
 			visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", submissionId });
 		}
diff --git a/web/src/app/ts/Roles.ts b/web/src/app/ts/Roles.ts
index af94e36..57a7d9d 100644
--- a/web/src/app/ts/Roles.ts
+++ b/web/src/app/ts/Roles.ts
@@ -1,15 +1,25 @@
-// Submissions roles bitflag
-enum Roles {
-  SubmissionUpload = 1 << 6,
-  SubmissionReview = 1 << 5,
-  SubmissionRelease = 1 << 4,
-  ScriptWrite = 1 << 3,
-  MapfixUpload = 1 << 2,
-  MapfixReview = 1 << 1,
-  MapDownload = 1 << 0,
-  Empty = 0
+type Roles = number;
+
+// Constants
+const RolesConstants = {
+  All: -1 as Roles,
+  SubmissionUpload: 1 << 6 as Roles,
+  SubmissionReview: 1 << 5 as Roles,
+  SubmissionRelease: 1 << 4 as Roles,
+  ScriptWrite: 1 << 3 as Roles,
+  MapfixUpload: 1 << 2 as Roles,
+  MapfixReview: 1 << 1 as Roles,
+  MapDownload: 1 << 0 as Roles,
+  Empty: 0 as Roles,
+};
+
+// Operations
+function hasRole(flags: Roles, role: Roles): boolean {
+  return (flags & role) === role;
 }
 
 export {
-	Roles,
-}
+  type Roles,
+  RolesConstants,
+  hasRole,
+};
-- 
2.47.1


From 6c2d759ca50faaeb511211066c4ff68bae03a9d1 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Fri, 4 Apr 2025 14:44:06 -0700
Subject: [PATCH 11/15] roles is json

---
 web/src/app/submissions/[submissionId]/_reviewButtons.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index d721b2e..0209ce3 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -72,11 +72,11 @@ export default function ReviewButtons(props: ReviewId) {
 		async function fetchData() {
 			try {
 				const [rolesData, userData] = await Promise.all([
-					fetch("/api/session/roles").then(rolesResponse => rolesResponse.text()).then(text => parseInt(text, 10)),
+					fetch("/api/session/roles").then(rolesResponse => rolesResponse.json()),
 					fetch("/api/session/user").then(userResponse => userResponse.json())
 				]);
 
-				setRoles(rolesData);
+				setRoles(rolesData.Roles);
 				setUser(userData.UserID);
 			} catch (error) {
 				console.error("Error fetching data:", error);
-- 
2.47.1


From 6328db7d14ce09a29acc4b1f5fc90ae0aaa14a23 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Fri, 4 Apr 2025 14:53:27 -0700
Subject: [PATCH 12/15] hide more buttons in specific cases

---
 .../submissions/[submissionId]/_reviewButtons.tsx  | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index 0209ce3..eb97f2a 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -92,7 +92,8 @@ export default function ReviewButtons(props: ReviewId) {
 
 	const visibleButtons: ReviewButton[] = [];
 
-	if (user === props.submissionSubmitter) {
+	const is_submitter = user === props.submissionSubmitter;
+	if (is_submitter) {
 		if ([SubmissionStatus.UnderConstruction, SubmissionStatus.ChangesRequested].includes(submissionStatus!)) {
 			visibleButtons.push({ name: "Submit", action: "submit", color: "info", submissionId });
 		}
@@ -102,7 +103,9 @@ export default function ReviewButtons(props: ReviewId) {
 	}
 
 	if (roles&RolesConstants.SubmissionReview) {
-		if (submissionStatus === SubmissionStatus.Submitted) {
+		// you can't review your own submission!
+		// note that this means there needs to be more than one person with SubmissionReview
+		if (!is_submitter && submissionStatus === SubmissionStatus.Submitted) {
 			visibleButtons.push({ name: "Accept", action: "trigger-validate", color: "info", submissionId });
 			visibleButtons.push({ name: "Reject", action: "reject", color: "error", submissionId });
 		}
@@ -112,7 +115,12 @@ export default function ReviewButtons(props: ReviewId) {
 		if (submissionStatus === SubmissionStatus.Validating) {
 			visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", submissionId });
 		}
-		if ([SubmissionStatus.Validated, SubmissionStatus.Accepted, SubmissionStatus.Submitted].includes(submissionStatus!)) {
+		// this button serves the same purpose as Revoke if you are both
+		// the map submitter and have SubmissionReview when status is Submitted
+		if (
+			[SubmissionStatus.Validated, SubmissionStatus.Accepted].includes(submissionStatus!)
+			|| !is_submitter && submissionStatus == SubmissionStatus.Submitted
+		) {
 			visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", submissionId });
 		}
 	}
-- 
2.47.1


From f38e5d32f9999b3a6317254afa686105202cfad6 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Fri, 4 Apr 2025 15:00:03 -0700
Subject: [PATCH 13/15] do it for mapfiex

---
 .../mapfixes/[mapfixId]/_reviewButtons.tsx    | 96 ++++++++++++++++---
 1 file changed, 83 insertions(+), 13 deletions(-)

diff --git a/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx b/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx
index 24d75c4..e62d42c 100644
--- a/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx
+++ b/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx
@@ -1,8 +1,11 @@
+import { Roles, RolesConstants } from "@/app/ts/Roles";
+import { MapfixStatus } from "@/app/ts/Mapfix";
 import { Button, ButtonOwnProps } from "@mui/material";
+import { useState, useEffect } from "react";
 
 type Actions    = "Completed" | "Submit" | "Reject" | "Revoke"
-type ApiActions = Lowercase<Actions> | "trigger-validate" | "retry-validate" | "trigger-upload" | "reset-uploading" | "reset-validating"
-type Review     = Actions | "Accept" | "Validate" | "Upload" | "Reset Uploading (fix softlocked status)" | "Reset Validating (fix softlocked status)" | "Request Changes"
+type ApiActions = Lowercase<Actions> | "request-changes" | "trigger-validate" | "retry-validate" | "trigger-upload" | "reset-uploading" | "reset-validating"
+type Review     = Actions | "Request Changes" | "Accept" | "Validate" | "Upload" | "Reset Uploading (fix softlocked status)" | "Reset Validating (fix softlocked status)" | "Request Changes"
 
 interface ReviewButton {
 	name: Review,
@@ -12,7 +15,9 @@ interface ReviewButton {
 }
 
 interface ReviewId {
-	mapfixId: string
+	mapfixId: string,
+	mapfixStatus: number,
+	mapfixSubmitter: number,
 }
 
 async function ReviewButtonClicked(action: ApiActions, mapfixId: string) {
@@ -45,7 +50,6 @@ function ReviewButton(props: ReviewButton) {
 }
 
 export default function ReviewButtons(props: ReviewId) {
-	const mapfixId = props.mapfixId
 	// When is each button visible?
 	// Multiple buttons can be visible at once.
 	// Action         | Role      | When Current Status is One of:
@@ -59,16 +63,82 @@ export default function ReviewButtons(props: ReviewId) {
 	// RequestChanges | Reviewer  | Validated, Accepted, Submitted
 	// Upload         | MapAdmin  | Validated
 	// ResetUploading | MapAdmin  | Uploading
+	const { mapfixId, mapfixStatus } = props;
+	const [user, setUser] = useState<number|null>(null);
+	const [roles, setRoles] = useState<Roles>(RolesConstants.Empty);
+	const [loading, setLoading] = useState(true);
+
+	useEffect(() => {
+		async function fetchData() {
+			try {
+				const [rolesData, userData] = await Promise.all([
+					fetch("/api/session/roles").then(rolesResponse => rolesResponse.json()),
+					fetch("/api/session/user").then(userResponse => userResponse.json())
+				]);
+
+				setRoles(rolesData.Roles);
+				setUser(userData.UserID);
+			} catch (error) {
+				console.error("Error fetching data:", error);
+			} finally {
+				setLoading(false);
+			}
+		}
+
+		fetchData();
+	}, [mapfixId]);
+
+	if (loading) return <p>Loading...</p>;
+
+	const visibleButtons: ReviewButton[] = [];
+
+	const is_submitter = user === props.mapfixSubmitter;
+	if (is_submitter) {
+		if ([MapfixStatus.UnderConstruction, MapfixStatus.ChangesRequested].includes(mapfixStatus!)) {
+			visibleButtons.push({ name: "Submit", action: "submit", color: "info", mapfixId });
+		}
+		if ([MapfixStatus.Submitted, MapfixStatus.ChangesRequested].includes(mapfixStatus!)) {
+			visibleButtons.push({ name: "Revoke", action: "revoke", color: "info", mapfixId });
+		}
+	}
+
+	if (roles&RolesConstants.MapfixReview) {
+		// you can't review your own mapfix!
+		// note that this means there needs to be more than one person with MapfixReview
+		if (!is_submitter && mapfixStatus === MapfixStatus.Submitted) {
+			visibleButtons.push({ name: "Accept", action: "trigger-validate", color: "info", mapfixId });
+			visibleButtons.push({ name: "Reject", action: "reject", color: "error", mapfixId });
+		}
+		if (mapfixStatus === MapfixStatus.Accepted) {
+			visibleButtons.push({ name: "Validate", action: "retry-validate", color: "info", mapfixId });
+		}
+		if (mapfixStatus === MapfixStatus.Validating) {
+			visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", mapfixId });
+		}
+		// this button serves the same purpose as Revoke if you are both
+		// the map submitter and have MapfixReview when status is Submitted
+		if (
+			[MapfixStatus.Validated, MapfixStatus.Accepted].includes(mapfixStatus!)
+			|| !is_submitter && mapfixStatus == MapfixStatus.Submitted
+		) {
+			visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", mapfixId });
+		}
+	}
+
+	if (roles&RolesConstants.MapfixUpload) {
+		if (mapfixStatus === MapfixStatus.Validated) {
+			visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", mapfixId });
+		}
+		if (mapfixStatus === MapfixStatus.Uploading) {
+			visibleButtons.push({ name: "Reset Uploading (fix softlocked status)", action: "reset-uploading", color: "error", mapfixId });
+		}
+	}
+
 	return (
 		<section className="review-set">
-			<ReviewButton color="info"  name="Submit"    action="submit"           mapfixId={mapfixId}/>
-			<ReviewButton color="info"  name="Revoke"    action="revoke"           mapfixId={mapfixId}/>
-			<ReviewButton color="info"  name="Accept"    action="trigger-validate" mapfixId={mapfixId}/>
-			<ReviewButton color="info"  name="Validate"  action="retry-validate"   mapfixId={mapfixId}/>
-			<ReviewButton color="error" name="Reject"    action="reject"           mapfixId={mapfixId}/>
-			<ReviewButton color="info"  name="Upload"    action="trigger-upload"   mapfixId={mapfixId}/>
-			<ReviewButton color="error" name="Reset Uploading (fix softlocked status)"    action="reset-uploading"   mapfixId={mapfixId}/>
-			<ReviewButton color="error" name="Reset Validating (fix softlocked status)"   action="reset-validating"  mapfixId={mapfixId}/>
+			{visibleButtons.map((btn) => (
+				<ReviewButton key={btn.action} {...btn} />
+			))}
 		</section>
-	)
+	);
 }
-- 
2.47.1


From 6aa0e85c0b630aa03600ca69e1c5b7fae1e31fb5 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Fri, 4 Apr 2025 15:02:46 -0700
Subject: [PATCH 14/15] page

---
 web/src/app/mapfixes/[mapfixId]/page.tsx | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/web/src/app/mapfixes/[mapfixId]/page.tsx b/web/src/app/mapfixes/[mapfixId]/page.tsx
index cc38cb3..43d3f2e 100644
--- a/web/src/app/mapfixes/[mapfixId]/page.tsx
+++ b/web/src/app/mapfixes/[mapfixId]/page.tsx
@@ -15,7 +15,9 @@ import { useState, useEffect } from "react";
 import "./(styles)/page.scss";
 
 interface ReviewId {
-	mapfixId: string
+	mapfixId: string,
+	mapfixStatus: number;
+	mapfixSubmitter: number,
 }
 
 function Ratings() {
@@ -46,7 +48,7 @@ function RatingArea(mapfix: ReviewId) {
          		<MapImage/>
          	</section>
             <Ratings/>
-			<ReviewButtons mapfixId={mapfix.mapfixId}/>
+			<ReviewButtons mapfixId={mapfix.mapfixId} mapfixStatus={mapfix.mapfixStatus} mapfixSubmitter={mapfix.mapfixSubmitter}/>
         </aside>
     )
 }
@@ -96,7 +98,7 @@ export default function MapfixInfoPage() {
         <Webpage>
             <main className="map-page-main">
                 <section className="review-section">
-					<RatingArea mapfixId={dynamicId.mapfixId}/>
+					<RatingArea mapfixId={dynamicId.mapfixId} mapfixStatus={mapfix.StatusID} mapfixSubmitter={mapfix.Submitter}/>
                     <TitleAndComments name={mapfix.DisplayName} creator={mapfix.Creator} review={mapfix.StatusID} status_message={mapfix.StatusMessage} asset_id={mapfix.AssetID} comments={[]}/>
                 </section>
             </main>
-- 
2.47.1


From 7990e25c0a087784fb91f02c01ec1b50a1a6dfb9 Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Fri, 4 Apr 2025 15:07:01 -0700
Subject: [PATCH 15/15] no available actions

---
 web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx     | 10 +++++++---
 .../app/submissions/[submissionId]/_reviewButtons.tsx  | 10 +++++++---
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx b/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx
index e62d42c..55480b6 100644
--- a/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx
+++ b/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx
@@ -136,9 +136,13 @@ export default function ReviewButtons(props: ReviewId) {
 
 	return (
 		<section className="review-set">
-			{visibleButtons.map((btn) => (
-				<ReviewButton key={btn.action} {...btn} />
-			))}
+			{visibleButtons.length === 0 ? (
+				<p>No available actions</p>
+			) : (
+				visibleButtons.map((btn) => (
+					<ReviewButton key={btn.action} {...btn} />
+				))
+			)}
 		</section>
 	);
 }
diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index eb97f2a..069cfd6 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -136,9 +136,13 @@ export default function ReviewButtons(props: ReviewId) {
 
 	return (
 		<section className="review-set">
-			{visibleButtons.map((btn) => (
-				<ReviewButton key={btn.action} {...btn} />
-			))}
+			{visibleButtons.length === 0 ? (
+				<p>No available actions</p>
+			) : (
+				visibleButtons.map((btn) => (
+					<ReviewButton key={btn.action} {...btn} />
+				))
+			)}
 		</section>
 	);
 }
-- 
2.47.1