From b97b245861b93a5ab5f8bde095d9920fabd0cbbd Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Mon, 12 Aug 2024 01:34:20 +0900
Subject: refactor(frontend): move some types to app/models

---
 frontend/app/components/ExecStatusIndicatorIcon.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'frontend/app/components/ExecStatusIndicatorIcon.tsx')

diff --git a/frontend/app/components/ExecStatusIndicatorIcon.tsx b/frontend/app/components/ExecStatusIndicatorIcon.tsx
index a76e957..c5b37f8 100644
--- a/frontend/app/components/ExecStatusIndicatorIcon.tsx
+++ b/frontend/app/components/ExecStatusIndicatorIcon.tsx
@@ -5,9 +5,10 @@ import {
 	faRotate,
 } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { VerificationResultStatus } from "../models/VerificationResult";
 
 type Props = {
-	status: string;
+	status: VerificationResultStatus;
 };
 
 export default function ExecStatusIndicatorIcon({ status }: Props) {
-- 
cgit v1.2.3-70-g09d2


From ab6abc3a7619be89dda1bc3ab0b3f19ff69b575f Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Mon, 12 Aug 2024 01:54:36 +0900
Subject: refactor(frontend): rename SubmissionResult and VerificationResult
 for consistant naming

---
 .../app/components/ExecStatusIndicatorIcon.tsx     |  4 +-
 frontend/app/components/GolfWatchApp.client.tsx    | 51 +++++++++---------
 .../GolfWatchApps/GolfWatchAppGaming.tsx           | 62 ++++++++++------------
 frontend/app/models/ExecResult.ts                  | 17 ++++++
 frontend/app/models/PlayerInfo.ts                  |  4 +-
 frontend/app/models/SubmissionResult.ts            | 38 -------------
 frontend/app/models/SubmitResult.ts                | 36 +++++++++++++
 frontend/app/models/VerificationResult.ts          | 17 ------
 8 files changed, 111 insertions(+), 118 deletions(-)
 create mode 100644 frontend/app/models/ExecResult.ts
 delete mode 100644 frontend/app/models/SubmissionResult.ts
 create mode 100644 frontend/app/models/SubmitResult.ts
 delete mode 100644 frontend/app/models/VerificationResult.ts

(limited to 'frontend/app/components/ExecStatusIndicatorIcon.tsx')

diff --git a/frontend/app/components/ExecStatusIndicatorIcon.tsx b/frontend/app/components/ExecStatusIndicatorIcon.tsx
index c5b37f8..b5c53ec 100644
--- a/frontend/app/components/ExecStatusIndicatorIcon.tsx
+++ b/frontend/app/components/ExecStatusIndicatorIcon.tsx
@@ -5,10 +5,10 @@ import {
 	faRotate,
 } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { VerificationResultStatus } from "../models/VerificationResult";
+import { ExecResultStatus } from "../models/ExecResult";
 
 type Props = {
-	status: VerificationResultStatus;
+	status: ExecResultStatus;
 };
 
 export default function ExecStatusIndicatorIcon({ status }: Props) {
diff --git a/frontend/app/components/GolfWatchApp.client.tsx b/frontend/app/components/GolfWatchApp.client.tsx
index 3f97d2a..7041572 100644
--- a/frontend/app/components/GolfWatchApp.client.tsx
+++ b/frontend/app/components/GolfWatchApp.client.tsx
@@ -78,14 +78,14 @@ export default function GolfWatchApp({
 		iconPath: playerA?.icon_path ?? null,
 		score: null,
 		code: "",
-		submissionResult: undefined,
+		submitResult: undefined,
 	});
 	const [playerInfoB, setPlayerInfoB] = useState<PlayerInfo>({
 		displayName: playerB?.display_name ?? null,
 		iconPath: playerB?.icon_path ?? null,
 		score: null,
 		code: "",
-		submissionResult: undefined,
+		submitResult: undefined,
 	});
 
 	if (readyState === ReadyState.UNINSTANTIATED) {
@@ -125,12 +125,12 @@ export default function GolfWatchApp({
 						player_id === playerA?.user_id ? setPlayerInfoA : setPlayerInfoB;
 					setter((prev) => ({
 						...prev,
-						submissionResult: {
+						submitResult: {
 							status: "running",
-							verificationResults: game.verification_steps.map((v) => ({
-								testcase_id: v.testcase_id,
+							execResults: game.verification_steps.map((r) => ({
+								testcase_id: r.testcase_id,
 								status: "running",
-								label: v.label,
+								label: r.label,
 								stdout: "",
 								stderr: "",
 							})),
@@ -143,21 +143,20 @@ export default function GolfWatchApp({
 						player_id === playerA?.user_id ? setPlayerInfoA : setPlayerInfoB;
 					setter((prev) => {
 						const ret = { ...prev };
-						if (ret.submissionResult === undefined) {
+						if (ret.submitResult === undefined) {
 							return ret;
 						}
-						ret.submissionResult = {
-							...ret.submissionResult,
-							verificationResults: ret.submissionResult.verificationResults.map(
-								(v) =>
-									v.testcase_id === testcase_id && v.status === "running"
-										? {
-												...v,
-												status,
-												stdout,
-												stderr,
-											}
-										: v,
+						ret.submitResult = {
+							...ret.submitResult,
+							execResults: ret.submitResult.execResults.map((r) =>
+								r.testcase_id === testcase_id && r.status === "running"
+									? {
+											...r,
+											status,
+											stdout,
+											stderr,
+										}
+									: r,
 							),
 						};
 						return ret;
@@ -168,11 +167,11 @@ export default function GolfWatchApp({
 						player_id === playerA?.user_id ? setPlayerInfoA : setPlayerInfoB;
 					setter((prev) => {
 						const ret = { ...prev };
-						if (ret.submissionResult === undefined) {
+						if (ret.submitResult === undefined) {
 							return ret;
 						}
-						ret.submissionResult = {
-							...ret.submissionResult,
+						ret.submitResult = {
+							...ret.submitResult,
 							status,
 						};
 						if (status === "success") {
@@ -182,10 +181,10 @@ export default function GolfWatchApp({
 								}
 							}
 						} else {
-							ret.submissionResult.verificationResults =
-								ret.submissionResult.verificationResults.map((v) =>
-									v.status === "running" ? { ...v, status: "canceled" } : v,
-								);
+							ret.submitResult.execResults = ret.submitResult.execResults.map(
+								(r) =>
+									r.status === "running" ? { ...r, status: "canceled" } : r,
+							);
 						}
 						return ret;
 					});
diff --git a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
index 5ca778b..bdd1ac3 100644
--- a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
+++ b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
@@ -1,5 +1,5 @@
 import { PlayerInfo } from "../../models/PlayerInfo";
-import { submissionResultStatusToLabel } from "../../models/SubmissionResult";
+import { submitResultStatusToLabel } from "../../models/SubmitResult";
 import ExecStatusIndicatorIcon from "../ExecStatusIndicatorIcon";
 
 type Props = {
@@ -60,28 +60,26 @@ export default function GolfWatchAppGaming({
 				</div>
 				<div>
 					<div>
-						{submissionResultStatusToLabel(
-							playerInfoA.submissionResult?.status ?? null,
+						{submitResultStatusToLabel(
+							playerInfoA.submitResult?.status ?? null,
 						)}
 					</div>
 					<div>
 						<ol>
-							{playerInfoA.submissionResult?.verificationResults.map(
-								(result) => (
-									<li key={result.testcase_id ?? -1}>
+							{playerInfoA.submitResult?.execResults.map((result) => (
+								<li key={result.testcase_id ?? -1}>
+									<div>
 										<div>
-											<div>
-												<ExecStatusIndicatorIcon status={result.status} />{" "}
-												{result.label}
-											</div>
-											<div>
-												{result.stdout}
-												{result.stderr}
-											</div>
+											<ExecStatusIndicatorIcon status={result.status} />{" "}
+											{result.label}
 										</div>
-									</li>
-								),
-							)}
+										<div>
+											{result.stdout}
+											{result.stderr}
+										</div>
+									</div>
+								</li>
+							))}
 						</ol>
 					</div>
 				</div>
@@ -92,28 +90,26 @@ export default function GolfWatchAppGaming({
 				</div>
 				<div>
 					<div>
-						{submissionResultStatusToLabel(
-							playerInfoB.submissionResult?.status ?? null,
+						{submitResultStatusToLabel(
+							playerInfoB.submitResult?.status ?? null,
 						)}
 					</div>
 					<div>
 						<ol>
-							{playerInfoB.submissionResult?.verificationResults.map(
-								(result, idx) => (
-									<li key={idx}>
+							{playerInfoB.submitResult?.execResults.map((result, idx) => (
+								<li key={idx}>
+									<div>
+										<div>
+											<ExecStatusIndicatorIcon status={result.status} />{" "}
+											{result.label}
+										</div>
 										<div>
-											<div>
-												<ExecStatusIndicatorIcon status={result.status} />{" "}
-												{result.label}
-											</div>
-											<div>
-												{result.stdout}
-												{result.stderr}
-											</div>
+											{result.stdout}
+											{result.stderr}
 										</div>
-									</li>
-								),
-							)}
+									</div>
+								</li>
+							))}
 						</ol>
 					</div>
 				</div>
diff --git a/frontend/app/models/ExecResult.ts b/frontend/app/models/ExecResult.ts
new file mode 100644
index 0000000..59b8ee8
--- /dev/null
+++ b/frontend/app/models/ExecResult.ts
@@ -0,0 +1,17 @@
+export type ExecResultStatus =
+	| "running"
+	| "success"
+	| "wrong_answer"
+	| "timeout"
+	| "compile_error"
+	| "runtime_error"
+	| "internal_error"
+	| "canceled";
+
+export type ExecResult = {
+	testcase_id: number | null;
+	status: ExecResultStatus;
+	label: string;
+	stdout: string;
+	stderr: string;
+};
diff --git a/frontend/app/models/PlayerInfo.ts b/frontend/app/models/PlayerInfo.ts
index 7206a8b..30cccea 100644
--- a/frontend/app/models/PlayerInfo.ts
+++ b/frontend/app/models/PlayerInfo.ts
@@ -1,9 +1,9 @@
-import type { SubmissionResult } from "./SubmissionResult";
+import type { SubmitResult } from "./SubmitResult";
 
 export type PlayerInfo = {
 	displayName: string | null;
 	iconPath: string | null;
 	score: number | null;
 	code: string | null;
-	submissionResult?: SubmissionResult;
+	submitResult?: SubmitResult;
 };
diff --git a/frontend/app/models/SubmissionResult.ts b/frontend/app/models/SubmissionResult.ts
deleted file mode 100644
index 7311494..0000000
--- a/frontend/app/models/SubmissionResult.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import type { VerificationResult } from "./VerificationResult";
-
-export type SubmissionResultStatus =
-	| "running"
-	| "success"
-	| "wrong_answer"
-	| "timeout"
-	| "compile_error"
-	| "runtime_error"
-	| "internal_error";
-
-export type SubmissionResult = {
-	status: SubmissionResultStatus;
-	verificationResults: VerificationResult[];
-};
-
-export function submissionResultStatusToLabel(
-	status: SubmissionResultStatus | null,
-) {
-	switch (status) {
-		case null:
-			return "-";
-		case "running":
-			return "Running...";
-		case "success":
-			return "Accepted";
-		case "wrong_answer":
-			return "Wrong Answer";
-		case "timeout":
-			return "Time Limit Exceeded";
-		case "compile_error":
-			return "Compile Error";
-		case "runtime_error":
-			return "Runtime Error";
-		case "internal_error":
-			return "Internal Error";
-	}
-}
diff --git a/frontend/app/models/SubmitResult.ts b/frontend/app/models/SubmitResult.ts
new file mode 100644
index 0000000..403a0db
--- /dev/null
+++ b/frontend/app/models/SubmitResult.ts
@@ -0,0 +1,36 @@
+import type { ExecResult } from "./ExecResult";
+
+export type SubmitResultStatus =
+	| "running"
+	| "success"
+	| "wrong_answer"
+	| "timeout"
+	| "compile_error"
+	| "runtime_error"
+	| "internal_error";
+
+export type SubmitResult = {
+	status: SubmitResultStatus;
+	execResults: ExecResult[];
+};
+
+export function submitResultStatusToLabel(status: SubmitResultStatus | null) {
+	switch (status) {
+		case null:
+			return "-";
+		case "running":
+			return "Running...";
+		case "success":
+			return "Accepted";
+		case "wrong_answer":
+			return "Wrong Answer";
+		case "timeout":
+			return "Time Limit Exceeded";
+		case "compile_error":
+			return "Compile Error";
+		case "runtime_error":
+			return "Runtime Error";
+		case "internal_error":
+			return "Internal Error";
+	}
+}
diff --git a/frontend/app/models/VerificationResult.ts b/frontend/app/models/VerificationResult.ts
deleted file mode 100644
index 09a7ef4..0000000
--- a/frontend/app/models/VerificationResult.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-export type VerificationResultStatus =
-	| "running"
-	| "success"
-	| "wrong_answer"
-	| "timeout"
-	| "compile_error"
-	| "runtime_error"
-	| "internal_error"
-	| "canceled";
-
-export type VerificationResult = {
-	testcase_id: number | null;
-	status: VerificationResultStatus;
-	label: string;
-	stdout: string;
-	stderr: string;
-};
-- 
cgit v1.2.3-70-g09d2


From 9f022ce7e59213284896a07a53bfef232a6e62d3 Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Mon, 12 Aug 2024 02:03:17 +0900
Subject: refactor(frontend): create SubmitStatusLabel component

---
 .../app/components/ExecStatusIndicatorIcon.tsx     |  2 +-
 .../GolfWatchApps/GolfWatchAppGaming.tsx           | 14 ++++++++-----
 frontend/app/components/SubmitStatusLabel.tsx      | 24 ++++++++++++++++++++++
 frontend/app/models/SubmitResult.ts                | 21 -------------------
 4 files changed, 34 insertions(+), 27 deletions(-)
 create mode 100644 frontend/app/components/SubmitStatusLabel.tsx

(limited to 'frontend/app/components/ExecStatusIndicatorIcon.tsx')

diff --git a/frontend/app/components/ExecStatusIndicatorIcon.tsx b/frontend/app/components/ExecStatusIndicatorIcon.tsx
index b5c53ec..13343b8 100644
--- a/frontend/app/components/ExecStatusIndicatorIcon.tsx
+++ b/frontend/app/components/ExecStatusIndicatorIcon.tsx
@@ -5,7 +5,7 @@ import {
 	faRotate,
 } from "@fortawesome/free-solid-svg-icons";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { ExecResultStatus } from "../models/ExecResult";
+import type { ExecResultStatus } from "../models/ExecResult";
 
 type Props = {
 	status: ExecResultStatus;
diff --git a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
index bdd1ac3..b436842 100644
--- a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
+++ b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
@@ -1,6 +1,6 @@
 import { PlayerInfo } from "../../models/PlayerInfo";
-import { submitResultStatusToLabel } from "../../models/SubmitResult";
 import ExecStatusIndicatorIcon from "../ExecStatusIndicatorIcon";
+import SubmitStatusLabel from "../SubmitStatusLabel";
 
 type Props = {
 	problem: string;
@@ -60,8 +60,10 @@ export default function GolfWatchAppGaming({
 				</div>
 				<div>
 					<div>
-						{submitResultStatusToLabel(
-							playerInfoA.submitResult?.status ?? null,
+						{playerInfoA.submitResult?.status ? (
+							<SubmitStatusLabel status={playerInfoA.submitResult?.status} />
+						) : (
+							<span>-</span>
 						)}
 					</div>
 					<div>
@@ -90,8 +92,10 @@ export default function GolfWatchAppGaming({
 				</div>
 				<div>
 					<div>
-						{submitResultStatusToLabel(
-							playerInfoB.submitResult?.status ?? null,
+						{playerInfoB.submitResult?.status ? (
+							<SubmitStatusLabel status={playerInfoB.submitResult?.status} />
+						) : (
+							<span>-</span>
 						)}
 					</div>
 					<div>
diff --git a/frontend/app/components/SubmitStatusLabel.tsx b/frontend/app/components/SubmitStatusLabel.tsx
new file mode 100644
index 0000000..f6e19bb
--- /dev/null
+++ b/frontend/app/components/SubmitStatusLabel.tsx
@@ -0,0 +1,24 @@
+import type { SubmitResultStatus } from "../models/SubmitResult";
+
+type Props = {
+	status: SubmitResultStatus;
+};
+
+export default function SubmitStatusLabel({ status }: Props) {
+	switch (status) {
+		case "running":
+			return <span>Running...</span>;
+		case "success":
+			return <span>Accepted</span>;
+		case "wrong_answer":
+			return <span>Wrong Answer</span>;
+		case "timeout":
+			return <span>Time Limit Exceeded</span>;
+		case "compile_error":
+			return <span>Compile Error</span>;
+		case "runtime_error":
+			return <span>Runtime Error</span>;
+		case "internal_error":
+			return <span>Internal Error</span>;
+	}
+}
diff --git a/frontend/app/models/SubmitResult.ts b/frontend/app/models/SubmitResult.ts
index 403a0db..0cb7f9b 100644
--- a/frontend/app/models/SubmitResult.ts
+++ b/frontend/app/models/SubmitResult.ts
@@ -13,24 +13,3 @@ export type SubmitResult = {
 	status: SubmitResultStatus;
 	execResults: ExecResult[];
 };
-
-export function submitResultStatusToLabel(status: SubmitResultStatus | null) {
-	switch (status) {
-		case null:
-			return "-";
-		case "running":
-			return "Running...";
-		case "success":
-			return "Accepted";
-		case "wrong_answer":
-			return "Wrong Answer";
-		case "timeout":
-			return "Time Limit Exceeded";
-		case "compile_error":
-			return "Compile Error";
-		case "runtime_error":
-			return "Runtime Error";
-		case "internal_error":
-			return "Internal Error";
-	}
-}
-- 
cgit v1.2.3-70-g09d2


From 699c5ce665bae6bcc406a0f7de994bb218a9977e Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Mon, 12 Aug 2024 02:08:55 +0900
Subject: feat(frontend): show submission result at first rendering

---
 .../app/components/ExecStatusIndicatorIcon.tsx     |  5 ++++
 frontend/app/components/GolfWatchApp.client.tsx    | 34 ++++++++++++++--------
 .../GolfWatchApps/GolfWatchAppGaming.tsx           | 12 ++------
 frontend/app/components/SubmitStatusLabel.tsx      |  2 ++
 frontend/app/models/ExecResult.ts                  |  1 +
 frontend/app/models/PlayerInfo.ts                  |  2 +-
 frontend/app/models/SubmitResult.ts                |  1 +
 7 files changed, 34 insertions(+), 23 deletions(-)

(limited to 'frontend/app/components/ExecStatusIndicatorIcon.tsx')

diff --git a/frontend/app/components/ExecStatusIndicatorIcon.tsx b/frontend/app/components/ExecStatusIndicatorIcon.tsx
index 13343b8..5277bfa 100644
--- a/frontend/app/components/ExecStatusIndicatorIcon.tsx
+++ b/frontend/app/components/ExecStatusIndicatorIcon.tsx
@@ -1,5 +1,6 @@
 import {
 	faBan,
+	faCircle,
 	faCircleCheck,
 	faCircleExclamation,
 	faRotate,
@@ -13,6 +14,10 @@ type Props = {
 
 export default function ExecStatusIndicatorIcon({ status }: Props) {
 	switch (status) {
+		case "waiting_submission":
+			return (
+				<FontAwesomeIcon icon={faCircle} fixedWidth className="text-gray-400" />
+			);
 		case "running":
 			return (
 				<FontAwesomeIcon
diff --git a/frontend/app/components/GolfWatchApp.client.tsx b/frontend/app/components/GolfWatchApp.client.tsx
index 481b997..7f582c9 100644
--- a/frontend/app/components/GolfWatchApp.client.tsx
+++ b/frontend/app/components/GolfWatchApp.client.tsx
@@ -78,14 +78,32 @@ export default function GolfWatchApp({
 		iconPath: playerA?.icon_path ?? null,
 		score: null,
 		code: "",
-		submitResult: undefined,
+		submitResult: {
+			status: "waiting_submission",
+			execResults: game.exec_steps.map((r) => ({
+				testcase_id: r.testcase_id,
+				status: "waiting_submission",
+				label: r.label,
+				stdout: "",
+				stderr: "",
+			})),
+		},
 	});
 	const [playerInfoB, setPlayerInfoB] = useState<PlayerInfo>({
 		displayName: playerB?.display_name ?? null,
 		iconPath: playerB?.icon_path ?? null,
 		score: null,
 		code: "",
-		submitResult: undefined,
+		submitResult: {
+			status: "waiting_submission",
+			execResults: game.exec_steps.map((r) => ({
+				testcase_id: r.testcase_id,
+				status: "waiting_submission",
+				label: r.label,
+				stdout: "",
+				stderr: "",
+			})),
+		},
 	});
 
 	if (readyState === ReadyState.UNINSTANTIATED) {
@@ -127,10 +145,9 @@ export default function GolfWatchApp({
 						...prev,
 						submitResult: {
 							status: "running",
-							execResults: game.exec_steps.map((r) => ({
-								testcase_id: r.testcase_id,
+							execResults: prev.submitResult.execResults.map((r) => ({
+								...r,
 								status: "running",
-								label: r.label,
 								stdout: "",
 								stderr: "",
 							})),
@@ -143,9 +160,6 @@ export default function GolfWatchApp({
 						player_id === playerA?.user_id ? setPlayerInfoA : setPlayerInfoB;
 					setter((prev) => {
 						const ret = { ...prev };
-						if (ret.submitResult === undefined) {
-							return ret;
-						}
 						ret.submitResult = {
 							...ret.submitResult,
 							execResults: ret.submitResult.execResults.map((r) =>
@@ -167,9 +181,6 @@ export default function GolfWatchApp({
 						player_id === playerA?.user_id ? setPlayerInfoA : setPlayerInfoB;
 					setter((prev) => {
 						const ret = { ...prev };
-						if (ret.submitResult === undefined) {
-							return ret;
-						}
 						ret.submitResult = {
 							...ret.submitResult,
 							status,
@@ -217,7 +228,6 @@ export default function GolfWatchApp({
 			}
 		}
 	}, [
-		game.exec_steps,
 		game.started_at,
 		lastJsonMessage,
 		readyState,
diff --git a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
index b436842..2a852e0 100644
--- a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
+++ b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
@@ -60,11 +60,7 @@ export default function GolfWatchAppGaming({
 				</div>
 				<div>
 					<div>
-						{playerInfoA.submitResult?.status ? (
-							<SubmitStatusLabel status={playerInfoA.submitResult?.status} />
-						) : (
-							<span>-</span>
-						)}
+						<SubmitStatusLabel status={playerInfoA.submitResult.status} />
 					</div>
 					<div>
 						<ol>
@@ -92,11 +88,7 @@ export default function GolfWatchAppGaming({
 				</div>
 				<div>
 					<div>
-						{playerInfoB.submitResult?.status ? (
-							<SubmitStatusLabel status={playerInfoB.submitResult?.status} />
-						) : (
-							<span>-</span>
-						)}
+						<SubmitStatusLabel status={playerInfoB.submitResult.status} />
 					</div>
 					<div>
 						<ol>
diff --git a/frontend/app/components/SubmitStatusLabel.tsx b/frontend/app/components/SubmitStatusLabel.tsx
index f6e19bb..2d4890d 100644
--- a/frontend/app/components/SubmitStatusLabel.tsx
+++ b/frontend/app/components/SubmitStatusLabel.tsx
@@ -6,6 +6,8 @@ type Props = {
 
 export default function SubmitStatusLabel({ status }: Props) {
 	switch (status) {
+		case "waiting_submission":
+			return <span>-</span>;
 		case "running":
 			return <span>Running...</span>;
 		case "success":
diff --git a/frontend/app/models/ExecResult.ts b/frontend/app/models/ExecResult.ts
index 59b8ee8..e0b6bb4 100644
--- a/frontend/app/models/ExecResult.ts
+++ b/frontend/app/models/ExecResult.ts
@@ -1,4 +1,5 @@
 export type ExecResultStatus =
+	| "waiting_submission"
 	| "running"
 	| "success"
 	| "wrong_answer"
diff --git a/frontend/app/models/PlayerInfo.ts b/frontend/app/models/PlayerInfo.ts
index 30cccea..8092ab3 100644
--- a/frontend/app/models/PlayerInfo.ts
+++ b/frontend/app/models/PlayerInfo.ts
@@ -5,5 +5,5 @@ export type PlayerInfo = {
 	iconPath: string | null;
 	score: number | null;
 	code: string | null;
-	submitResult?: SubmitResult;
+	submitResult: SubmitResult;
 };
diff --git a/frontend/app/models/SubmitResult.ts b/frontend/app/models/SubmitResult.ts
index 0cb7f9b..6df00b6 100644
--- a/frontend/app/models/SubmitResult.ts
+++ b/frontend/app/models/SubmitResult.ts
@@ -1,6 +1,7 @@
 import type { ExecResult } from "./ExecResult";
 
 export type SubmitResultStatus =
+	| "waiting_submission"
 	| "running"
 	| "success"
 	| "wrong_answer"
-- 
cgit v1.2.3-70-g09d2

