diff --git a/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx b/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx
index 008fc11..c9138c0 100644
--- a/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx
+++ b/web/src/app/mapfixes/[mapfixId]/_reviewButtons.tsx
@@ -3,13 +3,25 @@ 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> | "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 ReviewAction {
+	name: string,
+	action: string,
+}
+
+const ReviewActions = {
+	Submit: {name:"Submit",action:"trigger-submit"} as ReviewAction,
+	Revoke: {name:"Revoke",action:"revoke"} as ReviewAction,
+	Accept: {name:"Accept",action:"trigger-validate"} as ReviewAction,
+	Reject: {name:"Reject",action:"reject"} as ReviewAction,
+	Validate: {name:"Validate",action:"retry-validate"} as ReviewAction,
+	ResetValidating: {name:"Reset Validating (fix softlocked status)",action:"reset-validating"} as ReviewAction,
+	RequestChanges: {name:"Request Changes",action:"request-changes"} as ReviewAction,
+	Upload: {name:"Upload",action:"trigger-upload"} as ReviewAction,
+	ResetUploading: {name:"Reset Uploading (fix softlocked status)",action:"reset-uploading"} as ReviewAction,
+}
 
 interface ReviewButton {
-	name: Review,
-	action: ApiActions,
+	action: ReviewAction,
 	mapfixId: string,
 	color: ButtonOwnProps["color"]
 }
@@ -20,7 +32,7 @@ interface ReviewId {
 	mapfixSubmitter: number,
 }
 
-async function ReviewButtonClicked(action: ApiActions, mapfixId: string) {
+async function ReviewButtonClicked(action: string, mapfixId: string) {
 	try {
 		const response = await fetch(`/api/mapfixes/${mapfixId}/status/${action}`, {
 			method: "POST",
@@ -46,7 +58,7 @@ function ReviewButton(props: ReviewButton) {
 	return <Button
 		color={props.color}
 		variant="contained"
-		onClick={() => { ReviewButtonClicked(props.action, props.mapfixId) }}>{props.name}</Button>
+		onClick={() => { ReviewButtonClicked(props.action.action, props.mapfixId) }}>{props.action.name}</Button>
 }
 
 export default function ReviewButtons(props: ReviewId) {
@@ -95,10 +107,10 @@ export default function ReviewButtons(props: ReviewId) {
 	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 });
+			visibleButtons.push({ action: ReviewActions.Submit, color: "info", mapfixId });
 		}
 		if ([MapfixStatus.Submitted, MapfixStatus.ChangesRequested].includes(mapfixStatus!)) {
-			visibleButtons.push({ name: "Revoke", action: "revoke", color: "info", mapfixId });
+			visibleButtons.push({ action: ReviewActions.Revoke, color: "info", mapfixId });
 		}
 	}
 
@@ -106,14 +118,14 @@ export default function ReviewButtons(props: ReviewId) {
 		// 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 });
+			visibleButtons.push({ action: ReviewActions.Accept, color: "info", mapfixId });
+			visibleButtons.push({ action: ReviewActions.Reject, color: "error", mapfixId });
 		}
 		if (mapfixStatus === MapfixStatus.AcceptedUnvalidated) {
-			visibleButtons.push({ name: "Validate", action: "retry-validate", color: "info", mapfixId });
+			visibleButtons.push({ action: ReviewActions.Validate, color: "info", mapfixId });
 		}
 		if (mapfixStatus === MapfixStatus.Validating) {
-			visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", mapfixId });
+			visibleButtons.push({ action: ReviewActions.ResetValidating, 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
@@ -121,16 +133,16 @@ export default function ReviewButtons(props: ReviewId) {
 			[MapfixStatus.Validated, MapfixStatus.AcceptedUnvalidated].includes(mapfixStatus!)
 			|| !is_submitter && mapfixStatus == MapfixStatus.Submitted
 		) {
-			visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", mapfixId });
+			visibleButtons.push({ action: ReviewActions.RequestChanges, color: "error", mapfixId });
 		}
 	}
 
 	if (roles&RolesConstants.MapfixUpload) {
 		if (mapfixStatus === MapfixStatus.Validated) {
-			visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", mapfixId });
+			visibleButtons.push({ action: ReviewActions.Upload, color: "info", mapfixId });
 		}
 		if (mapfixStatus === MapfixStatus.Uploading) {
-			visibleButtons.push({ name: "Reset Uploading (fix softlocked status)", action: "reset-uploading", color: "error", mapfixId });
+			visibleButtons.push({ action: ReviewActions.ResetUploading, color: "error", mapfixId });
 		}
 	}
 
@@ -140,7 +152,7 @@ export default function ReviewButtons(props: ReviewId) {
 				<p>No available actions</p>
 			) : (
 				visibleButtons.map((btn) => (
-					<ReviewButton key={btn.action} {...btn} />
+					<ReviewButton key={btn.action.action} {...btn} />
 				))
 			)}
 		</section>
diff --git a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
index 345d435..aa68897 100644
--- a/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
+++ b/web/src/app/submissions/[submissionId]/_reviewButtons.tsx
@@ -3,13 +3,25 @@ import { SubmissionStatus } from "@/app/ts/Submission";
 import { Button, ButtonOwnProps } from "@mui/material";
 import { useState, useEffect } from "react";
 
-type Actions    = "Completed" | "Submit" | "Reject" | "Revoke"
-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 ReviewAction {
+	name: string,
+	action: string,
+}
+
+const ReviewActions = {
+	Submit: {name:"Submit",action:"trigger-submit"} as ReviewAction,
+	Revoke: {name:"Revoke",action:"revoke"} as ReviewAction,
+	Accept: {name:"Accept",action:"trigger-validate"} as ReviewAction,
+	Reject: {name:"Reject",action:"reject"} as ReviewAction,
+	Validate: {name:"Validate",action:"retry-validate"} as ReviewAction,
+	ResetValidating: {name:"Reset Validating (fix softlocked status)",action:"reset-validating"} as ReviewAction,
+	RequestChanges: {name:"Request Changes",action:"request-changes"} as ReviewAction,
+	Upload: {name:"Upload",action:"trigger-upload"} as ReviewAction,
+	ResetUploading: {name:"Reset Uploading (fix softlocked status)",action:"reset-uploading"} as ReviewAction,
+}
 
 interface ReviewButton {
-	name: Review,
-	action: ApiActions,
+	action: ReviewAction,
 	submissionId: string,
 	color: ButtonOwnProps["color"]
 }
@@ -20,7 +32,7 @@ interface ReviewId {
 	submissionSubmitter: number,
 }
 
-async function ReviewButtonClicked(action: ApiActions, submissionId: string) {
+async function ReviewButtonClicked(action: string, submissionId: string) {
 	try {
 		const response = await fetch(`/api/submissions/${submissionId}/status/${action}`, {
 			method: "POST",
@@ -46,7 +58,7 @@ function ReviewButton(props: ReviewButton) {
 	return <Button
 		color={props.color}
 		variant="contained"
-		onClick={() => { ReviewButtonClicked(props.action, props.submissionId) }}>{props.name}</Button>
+		onClick={() => { ReviewButtonClicked(props.action.action, props.submissionId) }}>{props.action.name}</Button>
 }
 
 export default function ReviewButtons(props: ReviewId) {
@@ -95,10 +107,10 @@ export default function ReviewButtons(props: ReviewId) {
 	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 });
+			visibleButtons.push({ action: ReviewActions.Submit, color: "info", submissionId });
 		}
 		if ([SubmissionStatus.Submitted, SubmissionStatus.ChangesRequested].includes(submissionStatus!)) {
-			visibleButtons.push({ name: "Revoke", action: "revoke", color: "info", submissionId });
+			visibleButtons.push({ action: ReviewActions.Revoke, color: "info", submissionId });
 		}
 	}
 
@@ -106,14 +118,14 @@ export default function ReviewButtons(props: ReviewId) {
 		// 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 });
+			visibleButtons.push({ action: ReviewActions.Accept, color: "info", submissionId });
+			visibleButtons.push({ action: ReviewActions.Reject, color: "error", submissionId });
 		}
 		if (submissionStatus === SubmissionStatus.AcceptedUnvalidated) {
-			visibleButtons.push({ name: "Validate", action: "retry-validate", color: "info", submissionId });
+			visibleButtons.push({ action: ReviewActions.Validate, color: "info", submissionId });
 		}
 		if (submissionStatus === SubmissionStatus.Validating) {
-			visibleButtons.push({ name: "Reset Validating (fix softlocked status)", action: "reset-validating", color: "error", submissionId });
+			visibleButtons.push({ action: ReviewActions.ResetValidating, color: "error", submissionId });
 		}
 		// this button serves the same purpose as Revoke if you are both
 		// the map submitter and have SubmissionReview when status is Submitted
@@ -121,17 +133,17 @@ export default function ReviewButtons(props: ReviewId) {
 			[SubmissionStatus.Validated, SubmissionStatus.AcceptedUnvalidated].includes(submissionStatus!)
 			|| !is_submitter && submissionStatus == SubmissionStatus.Submitted
 		) {
-			visibleButtons.push({ name: "Request Changes", action: "request-changes", color: "error", submissionId });
+			visibleButtons.push({ action: ReviewActions.RequestChanges, color: "error", submissionId });
 		}
 	}
 
 	if (roles&RolesConstants.SubmissionUpload) {
 		if (submissionStatus === SubmissionStatus.Validated) {
-			visibleButtons.push({ name: "Upload", action: "trigger-upload", color: "info", submissionId });
+			visibleButtons.push({ action: ReviewActions.Upload, color: "info", submissionId });
 		}
 		// TODO: hide Reset buttons for 10 seconds
 		if (submissionStatus === SubmissionStatus.Uploading) {
-			visibleButtons.push({ name: "Reset Uploading (fix softlocked status)", action: "reset-uploading", color: "error", submissionId });
+			visibleButtons.push({ action: ReviewActions.ResetUploading, color: "error", submissionId });
 		}
 	}
 
@@ -141,7 +153,7 @@ export default function ReviewButtons(props: ReviewId) {
 				<p>No available actions</p>
 			) : (
 				visibleButtons.map((btn) => (
-					<ReviewButton key={btn.action} {...btn} />
+					<ReviewButton key={btn.action.action} {...btn} />
 				))
 			)}
 		</section>