From 3840c6d8e4261f182657b11ba55f61da04d70b28 Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Wed, 31 Jul 2024 21:02:40 +0900
Subject: feat: implement /admin/games and /admin/games/{gameId}

---
 frontend/app/routes/admin.games_.$gameId.tsx | 127 +++++++++++++++++++++++++++
 1 file changed, 127 insertions(+)
 create mode 100644 frontend/app/routes/admin.games_.$gameId.tsx

(limited to 'frontend/app/routes/admin.games_.$gameId.tsx')

diff --git a/frontend/app/routes/admin.games_.$gameId.tsx b/frontend/app/routes/admin.games_.$gameId.tsx
new file mode 100644
index 0000000..5d83fb4
--- /dev/null
+++ b/frontend/app/routes/admin.games_.$gameId.tsx
@@ -0,0 +1,127 @@
+import type {
+  LoaderFunctionArgs,
+  MetaFunction,
+  ActionFunctionArgs,
+} from "@remix-run/node";
+import { useLoaderData, Form } from "@remix-run/react";
+import { isAuthenticated } from "../.server/auth";
+import { apiClient } from "../.server/api/client";
+
+export const meta: MetaFunction<typeof loader> = ({ data }) => {
+  return [
+    {
+      title: data
+        ? `[Admin] Game Edit ${data.game.display_name} | iOSDC 2024 Albatross.swift`
+        : "[Admin] Game Edit | iOSDC 2024 Albatross.swift",
+    },
+  ];
+};
+
+export async function loader({ request, params }: LoaderFunctionArgs) {
+  const { user, token } = await isAuthenticated(request, {
+    failureRedirect: "/login",
+  });
+  if (!user.is_admin) {
+    throw new Error("Unauthorized");
+  }
+  const { gameId } = params;
+  const { data, error } = await apiClient.GET("/admin/games/{game_id}", {
+    params: {
+      path: {
+        game_id: Number(gameId),
+      },
+      header: {
+        Authorization: `Bearer ${token}`,
+      },
+    },
+  });
+  if (error) {
+    throw new Error(error.message);
+  }
+  return { game: data.game };
+}
+
+export async function action({ request, params }: ActionFunctionArgs) {
+  const { user, token } = await isAuthenticated(request, {
+    failureRedirect: "/login",
+  });
+  if (!user.is_admin) {
+    throw new Error("Unauthorized");
+  }
+  const { gameId } = params;
+
+  const formData = await request.formData();
+  const action = formData.get("action");
+
+  const nextState =
+    action === "open"
+      ? "waiting_entries"
+      : action === "start"
+        ? "waiting_start"
+        : null;
+  if (!nextState) {
+    throw new Error("Invalid action");
+  }
+
+  const { error } = await apiClient.PUT("/admin/games/{game_id}", {
+    params: {
+      path: {
+        game_id: Number(gameId),
+      },
+      header: {
+        Authorization: `Bearer ${token}`,
+      },
+    },
+    body: {
+      state: nextState,
+    },
+  });
+  if (error) {
+    throw new Error(error.message);
+  }
+}
+
+export default function AdminGameEdit() {
+  const { game } = useLoaderData<typeof loader>()!;
+
+  return (
+    <div>
+      <div>
+        <h1>[Admin] Game Edit {game.display_name}</h1>
+        <ul>
+          <li>ID: {game.game_id}</li>
+          <li>State: {game.state}</li>
+          <li>Display Name: {game.display_name}</li>
+          <li>Duration Seconds: {game.duration_seconds}</li>
+          <li>
+            Started At:{" "}
+            {game.started_at
+              ? new Date(game.started_at * 1000).toString()
+              : "-"}
+          </li>
+          <li>Problem ID: {game.problem ? game.problem.problem_id : "-"}</li>
+        </ul>
+        <div>
+          <Form method="post">
+            <button
+              type="submit"
+              name="action"
+              value="open"
+              disabled={game.state !== "closed"}
+            >
+              Open
+            </button>
+            <button
+              type="submit"
+              name="action"
+              value="start"
+              disabled={game.state !== "waiting_start"}
+            >
+              Start
+            </button>
+          </Form>
+        </div>
+      </div>
+    </div>
+  );
+}
-- 
cgit v1.3.1

