aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/app/routes/login.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/app/routes/login.tsx')
-rw-r--r--frontend/app/routes/login.tsx150
1 files changed, 100 insertions, 50 deletions
diff --git a/frontend/app/routes/login.tsx b/frontend/app/routes/login.tsx
index d6414f7..b1249e0 100644
--- a/frontend/app/routes/login.tsx
+++ b/frontend/app/routes/login.tsx
@@ -3,8 +3,11 @@ import type {
LoaderFunctionArgs,
MetaFunction,
} from "@remix-run/node";
-import { Form, useLocation } from "@remix-run/react";
+import { Form, json, useActionData, useLocation } from "@remix-run/react";
import { ensureUserNotLoggedIn, login } from "../.server/auth";
+import BorderedContainer from "../components/BorderedContainer";
+import InputText from "../components/InputText";
+import SubmitButton from "../components/SubmitButton";
export const meta: MetaFunction = () => [
{ title: "Login | iOSDC Japan 2024 Albatross.swift" },
@@ -15,7 +18,42 @@ export async function loader({ request }: LoaderFunctionArgs) {
}
export async function action({ request }: ActionFunctionArgs) {
- await login(request);
+ const formData = await request.clone().formData();
+ const username = String(formData.get("username"));
+ const password = String(formData.get("password"));
+ if (username === "" || password === "") {
+ return json(
+ {
+ message: "ユーザー名またはパスワードが誤っています",
+ errors: {
+ username:
+ username === "" ? "ユーザー名を入力してください" : undefined,
+ password:
+ password === "" ? "パスワードを入力してください" : undefined,
+ },
+ },
+ { status: 400 },
+ );
+ }
+
+ try {
+ await login(request);
+ } catch (error) {
+ if (error instanceof Error) {
+ return json(
+ {
+ message: error.message,
+ errors: {
+ username: undefined,
+ password: undefined,
+ },
+ },
+ { status: 400 },
+ );
+ } else {
+ throw error;
+ }
+ }
return null;
}
@@ -24,56 +62,68 @@ export default function Login() {
const searchParams = new URLSearchParams(location.search);
const registrationToken = searchParams.get("registration_token");
+ const loginErrors = useActionData<typeof action>();
+
return (
<div className="min-h-screen bg-gray-100 flex items-center justify-center">
- <Form
- method="post"
- className="bg-white p-8 rounded shadow-md w-full max-w-sm"
- >
- <h2 className="text-2xl font-bold mb-6 text-center">Login</h2>
- <div className="mb-4">
- <label
- htmlFor="username"
- className="block text-sm font-medium text-gray-700"
- >
- Username
- </label>
- <input
- type="text"
- name="username"
- id="username"
- required
- className="mt-1 p-2 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"
- />
- </div>
- <div className="mb-6">
- <label
- htmlFor="password"
- className="block text-sm font-medium text-gray-700"
- >
- Password
- </label>
- <input
- type="password"
- name="password"
- id="password"
- autoComplete="current-password"
- required
- className="mt-1 p-2 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"
- />
- </div>
- <input
- type="hidden"
- name="registration_token"
- value={registrationToken ?? ""}
- />
- <button
- type="submit"
- className="w-full bg-blue-500 text-white py-2 rounded hover:bg-blue-600 transition duration-300"
- >
- Log In
- </button>
- </Form>
+ <div className="mx-2">
+ <BorderedContainer>
+ <Form method="post" className="w-full max-w-sm p-2">
+ <h2 className="text-2xl mb-6 text-center">
+ fortee アカウントでログイン
+ </h2>
+ <p className="text-sm mb-4">
+ fortee
+ のアカウントをお持ちでない場合は、イベントスタッフにお声がけください。
+ </p>
+ {loginErrors?.message && (
+ <p className="text-red-500 text-sm mb-4">{loginErrors.message}</p>
+ )}
+ <div className="mb-4 flex flex-col gap-1">
+ <label
+ htmlFor="username"
+ className="block text-sm font-medium text-gray-700"
+ >
+ ユーザー名
+ </label>
+ <InputText type="text" name="username" id="username" required />
+ {loginErrors?.errors?.username && (
+ <p className="text-red-500 text-sm">
+ {loginErrors.errors.username}
+ </p>
+ )}
+ </div>
+ <div className="mb-6 flex flex-col gap-1">
+ <label
+ htmlFor="password"
+ className="block text-sm font-medium text-gray-700"
+ >
+ パスワード
+ </label>
+ <InputText
+ type="password"
+ name="password"
+ id="password"
+ autoComplete="current-password"
+ required
+ />
+ {loginErrors?.errors?.password && (
+ <p className="text-red-500 text-sm">
+ {loginErrors.errors.password}
+ </p>
+ )}
+ </div>
+ <input
+ type="hidden"
+ name="registration_token"
+ value={registrationToken ?? ""}
+ />
+ <div className="flex justify-center">
+ <SubmitButton type="submit">ログイン</SubmitButton>
+ </div>
+ </Form>
+ </BorderedContainer>
+ </div>
</div>
);
}