135 lines
4.3 KiB
TypeScript
135 lines
4.3 KiB
TypeScript
"use client";
|
|
import React from "react";
|
|
import { z } from "zod";
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { useForm } from "react-hook-form";
|
|
import { useTranslations } from "next-intl";
|
|
import { Link, useRouter } from "@/shared/config/navigation";
|
|
import alert from "./icons/alert-circle.svg";
|
|
import Image from "next/image";
|
|
import eye_off from "./icons/eye-off.svg";
|
|
import eye_on from "./icons/eye-on.svg";
|
|
import Loader from "@/shared/ui/Loader/Loader";
|
|
import { signIn, useSession } from "next-auth/react";
|
|
|
|
const SignInForm = ({}) => {
|
|
const session = useSession();
|
|
const t = useTranslations("signIn");
|
|
const router = useRouter();
|
|
const [showPassword, setShowPassword] = React.useState(false);
|
|
const [loader, setLoader] = React.useState<boolean>(false);
|
|
const [error, setError] = React.useState<string>("");
|
|
|
|
const signInFormScheme = z.object({
|
|
email: z.string().email(t("emailFormat")),
|
|
password: z.string().min(8, t("passwordMin")),
|
|
});
|
|
|
|
type FormFields = z.infer<typeof signInFormScheme>;
|
|
|
|
const {
|
|
register,
|
|
handleSubmit,
|
|
formState: { errors, isSubmitting },
|
|
} = useForm<FormFields>({
|
|
resolver: zodResolver(signInFormScheme),
|
|
});
|
|
|
|
const onSubmit = async (data: FormFields) => {
|
|
setLoader(true);
|
|
const result = await signIn("credentials", {
|
|
redirect: false,
|
|
email: data.email,
|
|
password: data.password,
|
|
});
|
|
|
|
if (result?.error) {
|
|
setError(result.error);
|
|
} else if (result?.ok) {
|
|
router.push("/");
|
|
}
|
|
|
|
setLoader(false);
|
|
};
|
|
|
|
return (
|
|
<form
|
|
className="mb-2 w-[360px] flex flex-col"
|
|
onSubmit={handleSubmit(onSubmit)}
|
|
>
|
|
<div className="flex flex-col gap-5">
|
|
<div>
|
|
<label className="text-[14px] leading-5 text-gray-700">Email</label>
|
|
<div
|
|
className={`flex items-center${
|
|
errors.email?.message && "border border-red-400"
|
|
}`}
|
|
>
|
|
<input
|
|
placeholder="Email"
|
|
className="w-full text-[16px] leading-6 text-gray-900 px-[10px] py-[14px] border border-gray-300 rounded-lg shadow-sm bg-white"
|
|
type="text"
|
|
{...register("email", { required: true })}
|
|
/>
|
|
</div>
|
|
{errors?.email?.message && (
|
|
<p className="flex items-center justify-between text-[14px] font-normal leading-5 text-red-500">
|
|
{errors.email.message} <Image src={alert} alt="Alert Icon" />
|
|
</p>
|
|
)}
|
|
</div>
|
|
<div>
|
|
<label className="text-[14px] leading-5 text-gray-700">
|
|
{t("password")}
|
|
</label>
|
|
<div
|
|
className={`flex items-center border border-gray-300 rounded-lg shadow-sm bg-white${
|
|
errors?.password?.message && "border border-red-400"
|
|
}`}
|
|
>
|
|
<input
|
|
placeholder={t("password")}
|
|
className="w-full text-[16px] leading-6 text-gray-900 px-[10px] py-[14px]"
|
|
type={showPassword ? "text" : "password"}
|
|
{...register("password", { required: true })}
|
|
/>
|
|
<button
|
|
onClick={() => setShowPassword((prev) => !prev)}
|
|
type="button"
|
|
className="pr-2"
|
|
>
|
|
<Image src={showPassword ? eye_on : eye_off} alt="Eye Icon" />
|
|
</button>
|
|
</div>
|
|
{errors?.password?.message && (
|
|
<p className="flex items-center justify-between text-[14px] font-normal leading-5 text-red-500">
|
|
{errors.password.message} <Image src={alert} alt="Alert Icon" />
|
|
</p>
|
|
)}
|
|
</div>
|
|
{errors.root && (
|
|
<div className="text-red-500">{errors.root.message}</div>
|
|
)}
|
|
<div className="flex flex-col mt-[36px] gap-4">
|
|
<button
|
|
className="p-4 h-[50px] w-full font-bold leading-6 text-white bg-light-blue rounded-md"
|
|
type="submit"
|
|
>
|
|
{loader ? <Loader /> : t("loginBtn")}
|
|
</button>
|
|
</div>
|
|
<div className="text-blue font-semibold pt-2 cursor-pointer">
|
|
<Link
|
|
href="/sign-in/forgot-password"
|
|
className="text-blue font-semibold pt-2 cursor-pointer "
|
|
>
|
|
{t("passwordForget")}
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
);
|
|
};
|
|
|
|
export default SignInForm;
|