diff --git a/app/libs/getAccountCredentials.ts b/app/libs/getAccountCredentials.ts
new file mode 100644
index 0000000..5933964
--- /dev/null
+++ b/app/libs/getAccountCredentials.ts
@@ -0,0 +1,11 @@
+import type { SignInWithPasswordCredentials } from "@supabase/supabase-js";
+
+export function getAccountCredentials(
+ id: string,
+): SignInWithPasswordCredentials {
+ return {
+ // supabase は userId のみでサインインできないため、強引にやる
+ email: `email-${id}@example.com`,
+ password: "password",
+ };
+}
diff --git a/app/routes/_auth._index.tsx b/app/routes/_auth._index.tsx
new file mode 100644
index 0000000..02f871c
--- /dev/null
+++ b/app/routes/_auth._index.tsx
@@ -0,0 +1,43 @@
+import type { MetaFunction } from "@remix-run/node";
+import { useSession } from "~/hooks/useSession";
+
+export const meta: MetaFunction = () => {
+ return [
+ { title: "New Remix App" },
+ { name: "description", content: "Welcome to Remix!" },
+ ];
+};
+
+export default function Index() {
+ const session = useSession();
+
+ // 未サインインの場合
+ if (!session)
+ return (
+
+ Game
+
+
+ );
+
+ // サインイン済みの場合
+ return (
+
+ Game
+
+ Hello World
+
+
+ ID: {session.user.email?.replace("@example.com", "")}
+
+
+ );
+}
diff --git a/app/routes/_auth.tsx b/app/routes/_auth.tsx
new file mode 100644
index 0000000..996feb4
--- /dev/null
+++ b/app/routes/_auth.tsx
@@ -0,0 +1,17 @@
+import { Outlet, useNavigate } from "@remix-run/react";
+import { type ReactNode, useLayoutEffect } from "react";
+import { useSession } from "~/hooks/useSession";
+
+// _auth.**.tsx のパスへのアクセスは必ずここで前処理される
+export default function Layout(): ReactNode {
+ const navigate = useNavigate();
+ const session = useSession();
+
+ useLayoutEffect(() => {
+ if (!session) {
+ navigate("/signup");
+ }
+ }, [session, navigate]);
+
+ return ;
+}
diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx
deleted file mode 100644
index 76d0055..0000000
--- a/app/routes/_index.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import type { MetaFunction } from "@remix-run/node";
-
-export const meta: MetaFunction = () => {
- return [
- { title: "New Remix App" },
- { name: "description", content: "Welcome to Remix!" },
- ];
-};
-
-export default function Index() {
- return (
-
- );
-}
diff --git a/app/routes/_noauth.signin.tsx b/app/routes/_noauth.signin.tsx
new file mode 100644
index 0000000..c3f8269
--- /dev/null
+++ b/app/routes/_noauth.signin.tsx
@@ -0,0 +1,55 @@
+import { useNavigate } from "@remix-run/react";
+import type { ReactNode } from "react";
+import { useForm } from "react-hook-form";
+import { getAccountCredentials } from "~/libs/getAccountCredentials";
+import { supabase } from "~/libs/supabase";
+
+type FormValues = {
+ id: string;
+};
+
+export default function Signin(): ReactNode {
+ // ID でサインイン、デバッグ用(そもそもログアウトは想定していない)
+ const navigate = useNavigate();
+ const {
+ register,
+ handleSubmit,
+ formState: { errors },
+ } = useForm({
+ mode: "onBlur",
+ });
+
+ const onSubmit = async ({ id }: FormValues) => {
+ const { error } = await supabase.auth.signInWithPassword(
+ getAccountCredentials(id),
+ );
+
+ if (error) {
+ console.error(error);
+ return;
+ }
+
+ navigate("/");
+ };
+
+ return (
+
+ Game
+ ID でサインイン
+
+
+
+ );
+}
diff --git a/app/routes/_noauth.signup.tsx b/app/routes/_noauth.signup.tsx
new file mode 100644
index 0000000..d43eab7
--- /dev/null
+++ b/app/routes/_noauth.signup.tsx
@@ -0,0 +1,34 @@
+import { useNavigate } from "@remix-run/react";
+import { v4 } from "uuid";
+import { getAccountCredentials } from "~/libs/getAccountCredentials";
+import { supabase } from "~/libs/supabase";
+
+export default function Signup() {
+ const navigate = useNavigate();
+
+ const signUp = async () => {
+ const id = v4();
+ const { error } = await supabase.auth.signUp(getAccountCredentials(id));
+
+ if (error) {
+ console.error("Error signing up:", error.message);
+ return;
+ }
+
+ navigate("/");
+ };
+ return (
+
+ Game
+
+
+
+
+ );
+}
diff --git a/app/routes/_noauth.tsx b/app/routes/_noauth.tsx
new file mode 100644
index 0000000..24dd24a
--- /dev/null
+++ b/app/routes/_noauth.tsx
@@ -0,0 +1,19 @@
+import { Outlet, useNavigate } from "@remix-run/react";
+import type { ReactNode } from "react";
+import { useLayoutEffect } from "react";
+
+import { useSession } from "~/hooks/useSession";
+
+// _noauth.**.tsx のパスへのアクセスは必ずここで前処理される
+export default function Layout(): ReactNode {
+ const navigate = useNavigate();
+ const session = useSession();
+
+ useLayoutEffect(() => {
+ if (session) {
+ navigate("/");
+ }
+ }, [session, navigate]);
+
+ return ;
+}