Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
'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>
)
}