63 lines
3.5 KiB
TypeScript
63 lines
3.5 KiB
TypeScript
"use client";
|
|
import { useState, useTransition } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { useForm } from "react-hook-form";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { LoginFormData } from "./types";
|
|
import { loginSchemaEmail } from "./schemas";
|
|
import { loginTranslation } from "./language";
|
|
import { loginHook } from "./hook";
|
|
import { AuthPageProps } from "@/validations/mutual/auth/props";
|
|
|
|
function Login({ language }: AuthPageProps) {
|
|
const Router = useRouter();
|
|
const translation = loginTranslation[language];
|
|
|
|
const [isPending, startTransition] = useTransition();
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [jsonText, setJsonText] = useState<string | null>(null);
|
|
|
|
const { register, formState: { errors }, handleSubmit, } = useForm<LoginFormData>({ resolver: zodResolver(loginSchemaEmail) });
|
|
const onSubmit = async (data: LoginFormData) => { loginHook(startTransition, data, setError, setJsonText, Router, language) };
|
|
|
|
return (
|
|
<>
|
|
<div className="flex h-full min-h-[inherit] flex-col items-center justify-center gap-4">
|
|
<div className="w-full max-w-md rounded-lg bg-white p-8 shadow-md">
|
|
<h2 className="mb-6 text-center text-2xl font-bold text-gray-900">{translation.login}</h2>
|
|
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
|
|
<div>
|
|
<label htmlFor="email" className="block text-sm font-medium text-gray-700">{translation.email}</label>
|
|
<input {...register("email")} type="email" id="email" className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-indigo-500" />
|
|
{errors.email && (<p className="mt-1 text-sm text-red-600">{errors.email.message}</p>)}
|
|
</div>
|
|
<div>
|
|
<label htmlFor="password" className="block text-sm font-medium text-gray-700">{translation.password}</label>
|
|
<input {...register("password")} type="password" id="password" className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-indigo-500" />
|
|
{errors.password && (<p className="mt-1 text-sm text-red-600">{errors.password.message}</p>)}
|
|
</div>
|
|
{error && (<div className="rounded-md bg-red-50 p-4"><p className="text-sm text-red-700">{error}</p></div>)}
|
|
<button type="submit" disabled={isPending} className="w-full rounded-md bg-indigo-600 px-4 py-2 text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-50">
|
|
{isPending ? translation.pendingMessage : translation.login}</button>
|
|
</form>
|
|
</div>
|
|
{jsonText && (
|
|
<div className="w-full max-w-md rounded-lg bg-white p-8 shadow-md">
|
|
<h2 className="mb-4 text-center text-xl font-bold text-gray-900">{translation.responseData}</h2>
|
|
<div className="space-y-2">
|
|
{Object.entries(JSON.parse(jsonText)).map(([key, value]) => (
|
|
<div key={key} className="flex items-start gap-2">
|
|
<strong className="text-gray-700">{key}:</strong>
|
|
<span className="text-gray-600">{typeof value === "object" ? JSON.stringify(value) : value?.toString() || "N/A"}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default Login;
|