'use client' import { zodResolver } from "@hookform/resolvers/zod" import { signIn } from 'next-auth/react' import { useSearchParams } from 'next/navigation' import { HTMLAttributes, useState } from 'react' import { useForm } from 'react-hook-form' import * as z from "zod" import { Icons } from '@/components/icons' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { useToast } from '@/components/ui/use-toast' import { cn } from '@/lib/utils' import { userAuthSchema } from '@/lib/validations/auth' import { ToastAction } from "./ui/toast" interface UserAuthFormProps extends HTMLAttributes<HTMLDivElement> { type: "login" | "signup" } type FormData = z.infer<typeof userAuthSchema> export function UserAuthForm({ type, className, ...props }: UserAuthFormProps) { const { register, handleSubmit, formState: { errors }, } = useForm<FormData>({ resolver: zodResolver(userAuthSchema), }) const [isLoading, setIsLoading] = useState<boolean>(false) const [isGitHubLoading, setIsGitHubLoading] = useState<boolean>(false) const searchParams = useSearchParams() const { toast } = useToast() async function onSubmit(data: FormData) { setIsLoading(true) if (type === "signup") { const res = await fetch('/api/signup', { method: 'POST', body: JSON.stringify({ username: data.username, email: data.email, password: data.password }), headers: { 'Content-Type': 'application/json' } }) if (!res.ok) { setIsLoading(false) toast({ variant: "destructive", title: "Uh oh! Something went wrong.", description: "Your sign up request failed. Please try again.", }) } } const signInResult = await signIn("credentials", { username: data.username, email: data.email, password: data.password, redirect: false, callbackUrl: "/home", }); setIsLoading(false) if (!signInResult?.ok) { toast({ variant: "destructive", title: "Uh oh! Something went wrong.", description: "Your log in request failed. Please try again.", action: <ToastAction altText="Try again">Try again</ToastAction>, }) } // toast({ // title: "Check your email.", // description: "We sent you a login link. Be sure to check your spam too.", // }) } return ( <> <div className={cn("grid gap-6", className)} {...props}> <form onSubmit={handleSubmit(onSubmit)}> <div className="grid gap-2"> <div className="grid gap-1"> <Label className="sr-only" htmlFor="username"> Username </Label> <Input id="username" placeholder="Your username" type="username" autoCapitalize="none" autoComplete="username" autoCorrect="off" disabled={isLoading || isGitHubLoading} {...register("username")} /> {errors?.username && ( <p className="px-1 text-xs text-red-600"> {errors.username.message} </p> )} </div> {type === "signup" ? <div className="grid gap-1"> <Label className="sr-only" htmlFor="email"> Email </Label> <Input id="email" placeholder="Your email" type="email" autoCapitalize="none" autoComplete="email" autoCorrect="off" disabled={isLoading || isGitHubLoading} {...register("email")} /> {errors?.email && ( <p className="px-1 text-xs text-red-600"> {errors.email.message} </p> )} </div> : null} <div className="grid gap-1"> <Label className="sr-only" htmlFor="password"> Password </Label> <Input id="password" placeholder="Your password" type="password" autoCapitalize="none" autoComplete="new-password" autoCorrect="off" disabled={isLoading || isGitHubLoading} {...register("password")} /> {errors?.password && ( <p className="px-1 text-xs text-red-600"> {errors.password.message} </p> )} </div> <Button disabled={isLoading}> {isLoading && ( <Icons.spinner className="mr-2 h-4 w-4 animate-spin" /> )} {type === "signup" ? "Sign Up" : "Log In"} </Button> </div> </form> <div className="relative"> <div className="absolute inset-0 flex items-center"> <span className="w-full border-t" /> </div> <div className="relative flex justify-center text-xs uppercase"> <span className="bg-background px-2 text-muted-foreground"> Or continue with </span> </div> </div> <Button variant="outline" type="button" onClick={() => { setIsGitHubLoading(true) signIn("github") }} disabled={isLoading || isGitHubLoading} > {isGitHubLoading ? ( <Icons.spinner className="mr-2 h-4 w-4 animate-spin" /> ) : ( <Icons.github className="mr-2 h-4 w-4" /> )}{" "} Github </Button> </div> </> ) }