infoalloggi-monorepo/apps/infoalloggi/src/forms/FormLogin.tsx

213 lines
5.4 KiB
TypeScript
Raw Normal View History

2025-08-28 18:27:07 +02:00
import Link from "next/link";
import { useRouter } from "next/router";
import { useState } from "react";
import toast from "react-hot-toast";
import { z } from "zod/v4";
2025-08-04 17:45:44 +02:00
import {
2025-08-28 18:27:07 +02:00
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
2025-08-04 17:45:44 +02:00
} from "~/components/custom_ui/form";
import Input from "~/components/custom_ui/input";
import { LoadingSpinner } from "~/components/spinner";
2025-08-28 18:27:07 +02:00
import { Button } from "~/components/ui/button";
2025-08-04 17:45:44 +02:00
import { Checkbox } from "~/components/ui/checkbox";
import { env } from "~/env.mjs";
2025-08-28 18:27:07 +02:00
import { useZodForm } from "~/lib/zodForm";
import { useTranslation } from "~/providers/I18nProvider";
import { api } from "~/utils/api";
2025-08-04 17:45:44 +02:00
export const FormLogin = () => {
2025-08-28 18:27:07 +02:00
const router = useRouter();
const { redirect } = router.query;
const LoginSchema = z.object({
2025-08-29 16:18:32 +02:00
checkbox: z.boolean().refine((val) => val === false), // Honeypot field
2025-08-28 18:27:07 +02:00
email: z.email(),
password: z.string(),
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
type LoginFormValues = z.infer<typeof LoginSchema>;
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const defaultValues: LoginFormValues = {
2025-08-29 16:18:32 +02:00
checkbox: false, // Honeypot field
2025-08-28 18:27:07 +02:00
email: "",
password: "",
};
const { locale, t } = useTranslation();
z.config(z.locales[locale]());
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const form = useZodForm(LoginSchema, {
defaultValues: defaultValues,
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const utils = api.useUtils();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const { mutate, isPending } = api.auth.loginUser.useMutation({
2025-08-29 16:18:32 +02:00
onError: () => {
toast.error(t.auth.login.fail);
},
2025-08-28 18:27:07 +02:00
onSuccess: async () => {
await utils.auth.getSession.invalidate();
setAlreadyRequested(true);
toast.success(t.auth.login.success);
await router.push(redirect ? (redirect as string) : "/");
//window.location.replace(redirect ? (redirect as string) : "/");
2025-08-28 18:27:07 +02:00
},
});
const [altreadyRequested, setAlreadyRequested] = useState(false);
function onSubmit(fields: LoginFormValues) {
mutate({
email: fields.email,
password: fields.password,
});
form.reset();
}
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
return (
<>
<div className="text-center">
<div className="my-8 space-y-5">
<h3 className="text-3xl font-bold text-gray-800 sm:text-3xl">
{t.auth.login.titolo}
</h3>
<h3 className="text-xl">{t.auth.login.sottotitolo}</h3>
2025-08-28 18:27:07 +02:00
</div>
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
{env.NEXT_PUBLIC_BASE_URL.includes("localhost") && (
<button
className="bg-yellow-300 font-semibold"
onClick={async () => {
form.setValue("email", "m.pedone98@gmail.com");
form.setValue("password", "Marco1..");
await form.handleSubmit(onSubmit)();
}}
2025-08-29 16:18:32 +02:00
type="button"
2025-08-28 18:27:07 +02:00
>
TEMP DEV LOGIN
</button>
)}
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
<Form {...form}>
<form
autoComplete="on"
2025-08-29 16:18:32 +02:00
className="space-y-8 px-0.5"
onSubmit={form.handleSubmit(onSubmit)}
2025-08-28 18:27:07 +02:00
>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="email">{t.auth.login.email}</FormLabel>{" "}
<FormMessage />
</div>
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
<FormControl>
<Input
placeholder="esempio@email.com"
{...field}
autoComplete="username"
2025-08-29 16:18:32 +02:00
id="email"
2025-08-28 18:27:07 +02:00
required
2025-08-29 16:18:32 +02:00
type="email"
2025-08-28 18:27:07 +02:00
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel
className="flex flex-1 justify-between"
2025-08-29 16:18:32 +02:00
htmlFor="password"
2025-08-28 18:27:07 +02:00
>
<div>{t.auth.login.password}</div>
<Link
className="text-primary"
2025-08-29 16:18:32 +02:00
href="/auth/new-password-reset"
2025-08-28 18:27:07 +02:00
>
{t.auth.login.password_forgotten}
</Link>
</FormLabel>
<FormMessage />
</div>
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
<FormControl>
<Input
{...field}
2025-08-29 16:18:32 +02:00
autoComplete="current-password"
2025-08-28 18:27:07 +02:00
id="password"
required
2025-08-29 16:18:32 +02:00
type="password"
2025-08-28 18:27:07 +02:00
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="checkbox"
render={({ field }) => (
<FormItem className="hidden">
<div className="flex flex-wrap items-center gap-x-2">
<FormLabel htmlFor="checkbox">Check Me</FormLabel>
<FormMessage />
</div>
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
<FormControl>
<Checkbox
checked={field.value}
2025-08-29 16:18:32 +02:00
id="checkbox"
2025-08-28 18:27:07 +02:00
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<Button
2025-08-29 16:18:32 +02:00
className="w-full rounded-lg bg-indigo-600 px-4 py-2 font-medium text-white duration-150 hover:bg-indigo-500 active:bg-indigo-600"
2025-08-28 18:27:07 +02:00
disabled={isPending || altreadyRequested}
type="submit"
>
{isPending ? (
<div className="flex items-center justify-center">
<LoadingSpinner size={25} />
</div>
) : (
t.auth.login.titolo
)}
</Button>
</form>
</Form>
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
<br />
<div className="px-2 pt-2 text-left text-sm text-gray-500">
<span>{t.auth.login.psa_1}</span>
<Link
className="text-indigo-600 underline hover:text-indigo-500"
2025-08-29 16:18:32 +02:00
href="/termini-condizioni"
2025-08-28 18:27:07 +02:00
>
{t.auth.login.psa_terms}
</Link>
<span>{t.auth.login.psa_2}</span>
<Link
className="text-indigo-600 underline hover:text-indigo-500"
2025-08-29 16:18:32 +02:00
href="/privacy-policy"
2025-08-28 18:27:07 +02:00
>
{t.auth.login.psa_privacy}
</Link>
.
</div>
</div>
</>
);
2025-08-04 17:45:44 +02:00
};