'use client' import { zodResolver } from '@hookform/resolvers/zod' import { User } from '@prisma/client' import { useRouter } from 'next/navigation' import * as React from 'react' import { useForm } from 'react-hook-form' import * as z from 'zod' import { cn } from '@/lib/utils' import { UsernameValidator } from '@/lib/validations/username' import { useMutation } from '@tanstack/react-query' import axios, { AxiosError } from 'axios' import { Icons } from './icons' import { Button } from './ui/button' import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './ui/card' import { Input } from './ui/input' import { Label } from './ui/label' import { toast } from './ui/use-toast' interface UserNameFormProps extends React.HTMLAttributes<HTMLFormElement> { user: Pick<User, 'id' | 'username'> } type FormData = z.infer<typeof UsernameValidator> export function UserNameForm({ user, className, ...props }: UserNameFormProps) { const router = useRouter() const { handleSubmit, register, formState: { errors }, } = useForm<FormData>({ resolver: zodResolver(UsernameValidator), defaultValues: { name: user?.username || '', }, }) const { mutate: updateUsername, isLoading } = useMutation({ mutationFn: async ({ name }: FormData) => { const payload: FormData = { name } const { data } = await axios.patch(`/api/username/`, payload) return data }, onError: (err) => { if (err instanceof AxiosError) { if (err.response?.status === 409) { return toast({ title: 'Username already taken.', description: 'Please choose another username.', variant: 'destructive', }) } } return toast({ title: 'Something went wrong.', description: 'Your username was not updated. Please try again.', variant: 'destructive', }) }, onSuccess: () => { toast({ description: 'Your username has been updated.', }) router.refresh() }, }) return ( <form className={cn(className)} onSubmit={handleSubmit((e) => updateUsername(e))} {...props}> <Card> <CardHeader> <CardTitle>Your username</CardTitle> <CardDescription> Please enter a display name you are comfortable with. </CardDescription> </CardHeader> <CardContent> <div className='relative grid gap-1'> <div className='absolute top-0 left-0 w-8 h-10 grid place-items-center'> <span className='text-sm text-zinc-400'>@</span> </div> <Label className='sr-only' htmlFor='name'> Name </Label> <Input id='name' className='w-[400px] pl-6' size={32} {...register('name')} /> {errors?.name && ( <p className='px-1 text-xs text-red-600'>{errors.name.message}</p> )} </div> </CardContent> <CardFooter> <Button disabled={isLoading} type="submit"> {isLoading && ( <Icons.spinner className="mr-2 h-4 w-4 animate-spin" /> )} Change name </Button> </CardFooter> </Card> </form> ) }