infoalloggi-monorepo/apps/infoalloggi/src/forms/FormLogin.tsx
Marco Pedone 699579b432 feat: update environment variable handling and dependencies
- Added @t3-oss/env-nextjs for improved environment variable management.
- Updated zod to version 4.1.12 for enhanced validation capabilities.
- Upgraded jiti to version 2.6.1 for better module loading.
- Refactored environment variable imports from env.mjs to env.ts.
- Removed deprecated env.mjs file and replaced it with a new env.ts file using @t3-oss/env-nextjs.
- Adjusted various components and API routes to utilize the new environment variable structure.
- Updated next.config.js to support the new environment variable management.
- Modified Docker configuration to align with new BASE_URL handling.
2025-10-20 16:22:20 +02:00

212 lines
5.5 KiB
TypeScript

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";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "~/components/custom_ui/form";
import Input from "~/components/custom_ui/input";
import { LoadingSpinner } from "~/components/spinner";
import { Button } from "~/components/ui/button";
import { Checkbox } from "~/components/ui/checkbox";
import { env } from "~/env";
import { useZodForm } from "~/lib/zodForm";
import { useTranslation } from "~/providers/I18nProvider";
import { api } from "~/utils/api";
export const FormLogin = () => {
const router = useRouter();
const { redirect } = router.query;
const LoginSchema = z.object({
checkbox: z.boolean().refine((val) => val === false), // Honeypot field
email: z.email(),
password: z.string(),
});
type LoginFormValues = z.infer<typeof LoginSchema>;
const defaultValues: LoginFormValues = {
checkbox: false, // Honeypot field
email: "",
password: "",
};
const { locale, t } = useTranslation();
z.config(z.locales[locale]());
const form = useZodForm(LoginSchema, {
defaultValues: defaultValues,
});
const utils = api.useUtils();
const { mutate, isPending } = api.auth.loginUser.useMutation({
onError: ({ message }) => {
toast.error(`${t.auth.login.fail}\n${message}`);
},
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) : "/");
},
});
const [altreadyRequested, setAlreadyRequested] = useState(false);
function onSubmit(fields: LoginFormValues) {
mutate({
email: fields.email,
password: fields.password,
});
form.reset();
}
return (
<>
<div className="text-center">
<div className="my-8 space-y-5">
<h3 className="font-bold text-3xl text-gray-800 sm:text-3xl">
{t.auth.login.titolo}
</h3>
<h3 className="text-xl">{t.auth.login.sottotitolo}</h3>
</div>
{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)();
}}
type="button"
>
TEMP DEV LOGIN
</button>
)}
<Form {...form}>
<form
autoComplete="on"
className="space-y-8 px-0.5"
onSubmit={form.handleSubmit(onSubmit)}
>
<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>
<FormControl>
<Input
placeholder="esempio@email.com"
{...field}
autoComplete="username"
id="email"
required
type="email"
/>
</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"
htmlFor="password"
>
<div>{t.auth.login.password}</div>
<Link
className="text-primary"
href="/auth/new-password-reset"
>
{t.auth.login.password_forgotten}
</Link>
</FormLabel>
<FormMessage />
</div>
<FormControl>
<Input
{...field}
autoComplete="current-password"
id="password"
required
type="password"
/>
</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>
<FormControl>
<Checkbox
checked={field.value}
id="checkbox"
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<Button
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"
disabled={isPending || altreadyRequested}
type="submit"
>
{isPending ? (
<div className="flex items-center justify-center">
<LoadingSpinner size={25} />
</div>
) : (
t.auth.login.titolo
)}
</Button>
</form>
</Form>
<br />
<div className="px-2 pt-2 text-left text-gray-500 text-sm">
<span>{t.auth.login.psa_1}</span>
<Link
className="text-indigo-600 underline hover:text-indigo-500"
href="/termini-condizioni"
>
{t.auth.login.psa_terms}
</Link>
<span>{t.auth.login.psa_2}</span>
<Link
className="text-indigo-600 underline hover:text-indigo-500"
href="/privacy-policy"
>
{t.auth.login.psa_privacy}
</Link>
.
</div>
</div>
</>
);
};