@@ -2,11 +2,12 @@ import { zodResolver } from "@hookform/resolvers/zod";
2
2
import { env } from "next-runtime-env" ;
3
3
import { useEffect } from "react" ;
4
4
import { useForm } from "react-hook-form" ;
5
- import { HiXMark } from "react-icons/hi2" ;
5
+ import { HiCheck , HiMiniStar , HiXMark } from "react-icons/hi2" ;
6
6
import { z } from "zod" ;
7
7
8
8
import Button from "~/components/Button" ;
9
9
import Input from "~/components/Input" ;
10
+ import { useDebounce } from "~/hooks/useDebounce" ;
10
11
import { useModal } from "~/providers/modal" ;
11
12
import { usePopup } from "~/providers/popup" ;
12
13
import { api } from "~/utils/api" ;
@@ -50,6 +51,7 @@ export function UpdateBoardSlugForm({
50
51
register,
51
52
handleSubmit,
52
53
formState : { isDirty, errors } ,
54
+ watch,
53
55
} = useForm < FormValues > ( {
54
56
resolver : zodResolver ( schema ) ,
55
57
values : {
@@ -58,6 +60,10 @@ export function UpdateBoardSlugForm({
58
60
mode : "onChange" ,
59
61
} ) ;
60
62
63
+ const slug = watch ( "slug" ) ;
64
+
65
+ const [ debouncedSlug ] = useDebounce ( slug , 500 ) ;
66
+
61
67
const updateBoardSlug = api . board . update . useMutation ( {
62
68
onError : ( ) => {
63
69
showPopup ( {
@@ -72,13 +78,29 @@ export function UpdateBoardSlugForm({
72
78
} ,
73
79
} ) ;
74
80
81
+ const checkBoardSlugAvailability =
82
+ api . board . checkSlugAvailability . useQuery (
83
+ {
84
+ boardSlug : debouncedSlug ,
85
+ } ,
86
+ {
87
+ enabled :
88
+ ! ! debouncedSlug && debouncedSlug !== boardSlug && ! errors . slug ,
89
+ } ,
90
+ ) ;
91
+
92
+ const isBoardSlugAvailable = checkBoardSlugAvailability . data ;
93
+
75
94
useEffect ( ( ) => {
76
95
const nameElement : HTMLElement | null =
77
96
document . querySelector < HTMLElement > ( "#board-slug" ) ;
78
97
if ( nameElement ) nameElement . focus ( ) ;
79
98
} , [ ] ) ;
80
99
81
100
const onSubmit = ( data : FormValues ) => {
101
+ if ( ! isBoardSlugAvailable ) return ;
102
+ if ( isBoardSlugAvailable ?. isReserved ) return ;
103
+
82
104
updateBoardSlug . mutate ( {
83
105
slug : data . slug ,
84
106
boardPublicId,
@@ -107,14 +129,23 @@ export function UpdateBoardSlugForm({
107
129
< Input
108
130
id = "board-slug"
109
131
{ ...register ( "slug" ) }
110
- errorMessage = { errors . slug ?. message }
132
+ errorMessage = { errors . slug ?. message || ( isBoardSlugAvailable ?. isReserved
133
+ ? "This board URL has already been taken"
134
+ : undefined ) }
111
135
prefix = { `${ env ( "NEXT_PUBLIC_BASE_URL" ) } /${ workspaceSlug } /` }
112
136
onKeyDown = { async ( e ) => {
113
137
if ( e . key === "Enter" ) {
114
138
e . preventDefault ( ) ;
115
139
await handleSubmit ( onSubmit ) ( ) ;
116
140
}
117
141
} }
142
+ iconRight = {
143
+ ! ! errors . slug ?. message || isBoardSlugAvailable ?. isReserved ? (
144
+ < HiXMark className = "h-4 w-4 text-red-500" />
145
+ ) : (
146
+ < HiCheck className = "h-4 w-4 dark:text-dark-1000" />
147
+ )
148
+ }
118
149
/>
119
150
</ div >
120
151
< div className = "mt-12 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600" >
@@ -125,7 +156,8 @@ export function UpdateBoardSlugForm({
125
156
disabled = {
126
157
! isDirty ||
127
158
updateBoardSlug . isPending ||
128
- errors . slug ?. message !== undefined
159
+ errors . slug ?. message !== undefined ||
160
+ isBoardSlugAvailable ?. isReserved
129
161
}
130
162
>
131
163
Update
0 commit comments