peer-at-code-web/components/ui/UserAuthForm.tsx
2023-07-05 19:04:40 +02:00

196 lines
5.6 KiB
TypeScript

'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import cookies from 'js-cookie';
import { Loader2 } from 'lucide-react';
import { usePathname, useRouter } from 'next/navigation';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import * as z from 'zod';
import AppLink from '@/components/ui/AppLink';
import { Button } from '@/components/ui/Button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage
} from '@/components/ui/Form';
import { Input } from '@/components/ui/Input';
const AuthFormSchema = z.object({
pseudo: z.string().min(3, 'Votre pseudo doit faire au moins 3 caractères.'),
email: z.string().optional(),
passwd: z.string().min(8, 'Votre mot de passe doit faire au moins 8 caractères.'),
firstname: z.string().optional(),
lastname: z.string().optional()
});
export default function UserAuthForm() {
const form = useForm<z.infer<typeof AuthFormSchema>>({
resolver: zodResolver(AuthFormSchema),
defaultValues: {
pseudo: '',
email: '',
passwd: '',
firstname: '',
lastname: ''
}
});
const [isLoading, setIsLoading] = useState<boolean>(false);
const router = useRouter();
const pathname = usePathname()!;
const isSignIn = pathname.includes('sign-in');
async function onSubmit(data: z.infer<typeof AuthFormSchema>) {
setIsLoading(true);
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/${isSignIn ? 'login' : 'register'}`,
{
method: 'POST',
body: JSON.stringify(data)
}
);
if (!res) {
form.setError('passwd', {
type: 'manual',
message: "Une erreur s'est produite."
});
setIsLoading(false);
return;
}
if (!isSignIn) {
if (res.status === 400) {
const { username_valid, email_valid } = await res.json();
if (!username_valid) {
form.setError('pseudo', {
message: "Nom d'utilisateur indisponible"
});
setIsLoading(false);
return;
}
if (!email_valid) {
form.setError('email', {
message: 'Adresse e-mail indisponible'
});
setIsLoading(false);
return;
}
}
}
if (res.status === 200) {
const token = res.headers.get('Authorization')?.split(' ')[1];
if (token) {
cookies.set('token', token, {
sameSite: 'strict',
secure: process.env.NODE_ENV === 'production'
});
router.refresh();
}
} else {
form.setError('passwd', {
message: "Nom d'utilisateur ou mot de passe incorrect"
});
setIsLoading(false);
return;
}
}
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex w-52 flex-col justify-center space-y-4 sm:w-72"
>
{!isSignIn && (
<>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel htmlFor="email">Email</FormLabel>
<FormControl>
<Input type="email" placeholder="philipzcwbarlow@peerat.dev" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="firstname"
render={({ field }) => (
<FormItem>
<FormLabel htmlFor="firstname">Prénom</FormLabel>
<FormControl>
<Input placeholder="Philip" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="lastname"
render={({ field }) => (
<FormItem>
<FormLabel htmlFor="lastname">Nom</FormLabel>
<FormControl>
<Input placeholder="Barlow" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</>
)}
<FormField
control={form.control}
name="pseudo"
render={({ field }) => (
<FormItem>
<FormLabel htmlFor="pseudo">Nom d&apos;utilisateur</FormLabel>
<FormControl>
<Input placeholder="Barlow" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="passwd"
render={({ field }) => (
<FormItem>
<FormLabel htmlFor="passwd">Mot de passe</FormLabel>
<FormControl>
<Input type="password" placeholder="********" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button disabled={isLoading} variant="brand">
{isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
{isSignIn ? 'Se connecter' : "S'inscrire"}
</Button>
<p className="flex flex-col items-center text-sm text-muted">
{isSignIn ? "Vous n'avez pas de compte?" : 'Vous possédez un compte?'}{' '}
<AppLink className="text-brand underline" href={isSignIn ? '/sign-up' : '/sign-in'}>
{isSignIn ? "S'inscrire maintenant" : 'Se connecter'}
</AppLink>
</p>
</form>
</Form>
);
}