1
+ import { useMutation , useQueryClient } from "@tanstack/react-query"
2
+ import { Controller , type SubmitHandler , useForm } from "react-hook-form"
3
+
1
4
import {
2
5
Button ,
3
- Checkbox ,
6
+ DialogActionTrigger ,
7
+ DialogTitle ,
4
8
Flex ,
5
- FormControl ,
6
- FormErrorMessage ,
7
- FormLabel ,
8
9
Input ,
9
- Modal ,
10
- ModalBody ,
11
- ModalCloseButton ,
12
- ModalContent ,
13
- ModalFooter ,
14
- ModalHeader ,
15
- ModalOverlay ,
10
+ Text ,
11
+ VStack ,
16
12
} from "@chakra-ui/react"
17
- import { useMutation , useQueryClient } from "@tanstack/react-query"
18
- import { type SubmitHandler , useForm } from "react-hook-form"
19
-
13
+ import { useState } from "react"
14
+ import { FaPlus } from "react-icons/fa"
20
15
import { type UserCreate , UsersService } from "../../client"
21
16
import type { ApiError } from "../../client/core/ApiError"
22
17
import useCustomToast from "../../hooks/useCustomToast"
23
18
import { emailPattern , handleError } from "../../utils"
24
-
25
- interface AddUserProps {
26
- isOpen : boolean
27
- onClose : ( ) => void
28
- }
19
+ import { Checkbox } from "../ui/checkbox"
20
+ import {
21
+ DialogBody ,
22
+ DialogCloseTrigger ,
23
+ DialogContent ,
24
+ DialogFooter ,
25
+ DialogHeader ,
26
+ DialogRoot ,
27
+ DialogTrigger ,
28
+ } from "../ui/dialog"
29
+ import { Field } from "../ui/field"
29
30
30
31
interface UserCreateForm extends UserCreate {
31
32
confirm_password : string
32
33
}
33
34
34
- const AddUser = ( { isOpen, onClose } : AddUserProps ) => {
35
+ const AddUser = ( ) => {
36
+ const [ isOpen , setIsOpen ] = useState ( false )
35
37
const queryClient = useQueryClient ( )
36
- const showToast = useCustomToast ( )
38
+ const { showSuccessToast } = useCustomToast ( )
37
39
const {
40
+ control,
38
41
register,
39
42
handleSubmit,
40
43
reset,
41
44
getValues,
42
- formState : { errors, isSubmitting } ,
45
+ formState : { errors, isValid , isSubmitting } ,
43
46
} = useForm < UserCreateForm > ( {
44
47
mode : "onBlur" ,
45
48
criteriaMode : "all" ,
@@ -57,12 +60,12 @@ const AddUser = ({ isOpen, onClose }: AddUserProps) => {
57
60
mutationFn : ( data : UserCreate ) =>
58
61
UsersService . createUser ( { requestBody : data } ) ,
59
62
onSuccess : ( ) => {
60
- showToast ( "Success!" , " User created successfully." , "success ")
63
+ showSuccessToast ( " User created successfully.")
61
64
reset ( )
62
- onClose ( )
65
+ setIsOpen ( false )
63
66
} ,
64
67
onError : ( err : ApiError ) => {
65
- handleError ( err , showToast )
68
+ handleError ( err )
66
69
} ,
67
70
onSettled : ( ) => {
68
71
queryClient . invalidateQueries ( { queryKey : [ "users" ] } )
@@ -74,108 +77,153 @@ const AddUser = ({ isOpen, onClose }: AddUserProps) => {
74
77
}
75
78
76
79
return (
77
- < >
78
- < Modal
79
- isOpen = { isOpen }
80
- onClose = { onClose }
81
- size = { { base : "sm" , md : "md" } }
82
- isCentered
83
- >
84
- < ModalOverlay />
85
- < ModalContent as = "form" onSubmit = { handleSubmit ( onSubmit ) } >
86
- < ModalHeader > Add User</ ModalHeader >
87
- < ModalCloseButton />
88
- < ModalBody pb = { 6 } >
89
- < FormControl isRequired isInvalid = { ! ! errors . email } >
90
- < FormLabel htmlFor = "email" > Email</ FormLabel >
91
- < Input
92
- id = "email"
93
- { ...register ( "email" , {
94
- required : "Email is required" ,
95
- pattern : emailPattern ,
96
- } ) }
97
- placeholder = "Email"
98
- type = "email"
99
- />
100
- { errors . email && (
101
- < FormErrorMessage > { errors . email . message } </ FormErrorMessage >
102
- ) }
103
- </ FormControl >
104
- < FormControl mt = { 4 } isInvalid = { ! ! errors . full_name } >
105
- < FormLabel htmlFor = "name" > Full name</ FormLabel >
106
- < Input
107
- id = "name"
108
- { ...register ( "full_name" ) }
109
- placeholder = "Full name"
110
- type = "text"
111
- />
112
- { errors . full_name && (
113
- < FormErrorMessage > { errors . full_name . message } </ FormErrorMessage >
114
- ) }
115
- </ FormControl >
116
- < FormControl mt = { 4 } isRequired isInvalid = { ! ! errors . password } >
117
- < FormLabel htmlFor = "password" > Set Password</ FormLabel >
118
- < Input
119
- id = "password"
120
- { ...register ( "password" , {
121
- required : "Password is required" ,
122
- minLength : {
123
- value : 8 ,
124
- message : "Password must be at least 8 characters" ,
125
- } ,
126
- } ) }
127
- placeholder = "Password"
128
- type = "password"
80
+ < DialogRoot
81
+ size = { { base : "xs" , md : "md" } }
82
+ placement = "center"
83
+ open = { isOpen }
84
+ onOpenChange = { ( { open } ) => setIsOpen ( open ) }
85
+ >
86
+ < DialogTrigger asChild >
87
+ < Button value = "add-user" my = { 4 } >
88
+ < FaPlus fontSize = "16px" />
89
+ Add User
90
+ </ Button >
91
+ </ DialogTrigger >
92
+ < DialogContent >
93
+ < form onSubmit = { handleSubmit ( onSubmit ) } >
94
+ < DialogHeader >
95
+ < DialogTitle > Add User</ DialogTitle >
96
+ </ DialogHeader >
97
+ < DialogBody >
98
+ < Text mb = { 4 } >
99
+ Fill in the form below to add a new user to the system.
100
+ </ Text >
101
+ < VStack gap = { 4 } >
102
+ < Field
103
+ required
104
+ invalid = { ! ! errors . email }
105
+ errorText = { errors . email ?. message }
106
+ label = "Email"
107
+ >
108
+ < Input
109
+ id = "email"
110
+ { ...register ( "email" , {
111
+ required : "Email is required" ,
112
+ pattern : emailPattern ,
113
+ } ) }
114
+ placeholder = "Email"
115
+ type = "email"
116
+ />
117
+ </ Field >
118
+
119
+ < Field
120
+ invalid = { ! ! errors . full_name }
121
+ errorText = { errors . full_name ?. message }
122
+ label = "Full Name"
123
+ >
124
+ < Input
125
+ id = "name"
126
+ { ...register ( "full_name" ) }
127
+ placeholder = "Full name"
128
+ type = "text"
129
+ />
130
+ </ Field >
131
+
132
+ < Field
133
+ required
134
+ invalid = { ! ! errors . password }
135
+ errorText = { errors . password ?. message }
136
+ label = "Set Password"
137
+ >
138
+ < Input
139
+ id = "password"
140
+ { ...register ( "password" , {
141
+ required : "Password is required" ,
142
+ minLength : {
143
+ value : 8 ,
144
+ message : "Password must be at least 8 characters" ,
145
+ } ,
146
+ } ) }
147
+ placeholder = "Password"
148
+ type = "password"
149
+ />
150
+ </ Field >
151
+
152
+ < Field
153
+ required
154
+ invalid = { ! ! errors . confirm_password }
155
+ errorText = { errors . confirm_password ?. message }
156
+ label = "Confirm Password"
157
+ >
158
+ < Input
159
+ id = "confirm_password"
160
+ { ...register ( "confirm_password" , {
161
+ required : "Please confirm your password" ,
162
+ validate : ( value ) =>
163
+ value === getValues ( ) . password ||
164
+ "The passwords do not match" ,
165
+ } ) }
166
+ placeholder = "Password"
167
+ type = "password"
168
+ />
169
+ </ Field >
170
+ </ VStack >
171
+
172
+ < Flex mt = { 4 } direction = "column" gap = { 4 } >
173
+ < Controller
174
+ control = { control }
175
+ name = "is_superuser"
176
+ render = { ( { field } ) => (
177
+ < Field disabled = { field . disabled } colorPalette = "teal" >
178
+ < Checkbox
179
+ checked = { field . value }
180
+ onCheckedChange = { ( { checked } ) => field . onChange ( checked ) }
181
+ >
182
+ Is superuser?
183
+ </ Checkbox >
184
+ </ Field >
185
+ ) }
129
186
/>
130
- { errors . password && (
131
- < FormErrorMessage > { errors . password . message } </ FormErrorMessage >
132
- ) }
133
- </ FormControl >
134
- < FormControl
135
- mt = { 4 }
136
- isRequired
137
- isInvalid = { ! ! errors . confirm_password }
138
- >
139
- < FormLabel htmlFor = "confirm_password" > Confirm Password</ FormLabel >
140
- < Input
141
- id = "confirm_password"
142
- { ...register ( "confirm_password" , {
143
- required : "Please confirm your password" ,
144
- validate : ( value ) =>
145
- value === getValues ( ) . password ||
146
- "The passwords do not match" ,
147
- } ) }
148
- placeholder = "Password"
149
- type = "password"
187
+ < Controller
188
+ control = { control }
189
+ name = "is_active"
190
+ render = { ( { field } ) => (
191
+ < Field disabled = { field . disabled } colorPalette = "teal" >
192
+ < Checkbox
193
+ checked = { field . value }
194
+ onCheckedChange = { ( { checked } ) => field . onChange ( checked ) }
195
+ >
196
+ Is active?
197
+ </ Checkbox >
198
+ </ Field >
199
+ ) }
150
200
/>
151
- { errors . confirm_password && (
152
- < FormErrorMessage >
153
- { errors . confirm_password . message }
154
- </ FormErrorMessage >
155
- ) }
156
- </ FormControl >
157
- < Flex mt = { 4 } >
158
- < FormControl >
159
- < Checkbox { ...register ( "is_superuser" ) } colorScheme = "teal" >
160
- Is superuser?
161
- </ Checkbox >
162
- </ FormControl >
163
- < FormControl >
164
- < Checkbox { ...register ( "is_active" ) } colorScheme = "teal" >
165
- Is active?
166
- </ Checkbox >
167
- </ FormControl >
168
201
</ Flex >
169
- </ ModalBody >
170
- < ModalFooter gap = { 3 } >
171
- < Button variant = "primary" type = "submit" isLoading = { isSubmitting } >
202
+ </ DialogBody >
203
+
204
+ < DialogFooter gap = { 2 } >
205
+ < DialogActionTrigger asChild >
206
+ < Button
207
+ variant = "subtle"
208
+ colorPalette = "gray"
209
+ disabled = { isSubmitting }
210
+ >
211
+ Cancel
212
+ </ Button >
213
+ </ DialogActionTrigger >
214
+ < Button
215
+ variant = "solid"
216
+ type = "submit"
217
+ disabled = { ! isValid }
218
+ loading = { isSubmitting }
219
+ >
172
220
Save
173
221
</ Button >
174
- < Button onClick = { onClose } > Cancel </ Button >
175
- </ ModalFooter >
176
- </ ModalContent >
177
- </ Modal >
178
- </ >
222
+ </ DialogFooter >
223
+ </ form >
224
+ < DialogCloseTrigger / >
225
+ </ DialogContent >
226
+ </ DialogRoot >
179
227
)
180
228
}
181
229
0 commit comments