1
- import CheckIcon from "@mui/icons-material/Check" ;
2
- import ContentCopyIcon from "@mui/icons-material/ContentCopy" ;
3
- import LockOutlinedIcon from "@mui/icons-material/LockOutlined" ;
4
1
import {
5
- Alert ,
6
- Avatar ,
7
- Box ,
8
2
Button ,
9
3
Dialog ,
10
4
DialogActions ,
11
5
DialogContent ,
12
6
DialogContentText ,
13
7
DialogTitle ,
14
- TextField ,
15
- Typography ,
16
8
} from "@mui/material" ;
17
- import React , { useState } from "react" ;
18
-
19
- interface User {
20
- username : string ;
21
- recovery_codes : string [ ] ;
22
- }
23
- interface RegisterModalProps {
24
- open : boolean ;
25
- onClose : ( event : { } , reason : string ) => void ;
26
- onContinue : ( recoveryCodes : string [ ] ) => void ;
27
- registerUser : ( username : string , password : string ) => Promise < User > ;
28
- }
29
-
30
- function RegisterModal ( {
31
- open,
32
- onClose,
33
- onContinue,
34
- registerUser,
35
- } : RegisterModalProps ) {
36
- const [ username , setUsername ] = useState ( "" ) ;
37
- const [ password , setPassword ] = useState ( "" ) ;
38
- const [ confirmPassword , setConfirmPassword ] = useState ( "" ) ;
39
- const [ errorMessage , setErrorMessage ] = useState ( "" ) ;
40
- const [ errors , setErrors ] = React . useState ( {
41
- username : false ,
42
- password : false ,
43
- confirmPassword : false ,
44
- confirmPasswordMatch : false ,
45
- } ) ;
46
- const validateForm = ( ) => {
47
- const newErrors = {
48
- username : username === "" ,
49
- password : password === "" ,
50
- confirmPassword : confirmPassword === "" ,
51
- confirmPasswordMatch : password !== confirmPassword ,
52
- } ;
53
- setErrors ( newErrors ) ;
54
- return Object . values ( newErrors ) . every ( ( value ) => value === false ) ;
55
- } ;
56
- const handleRegister = async ( event : React . MouseEvent < HTMLButtonElement > ) => {
57
- event . preventDefault ( ) ;
58
- if ( validateForm ( ) ) {
59
- console . log ( "Registering user" ) ;
60
-
61
- const data = await registerUser ( username , password ) ;
62
- if ( data && data . username ) {
63
- onContinue ( data . recovery_codes ) ;
64
- } else {
65
- setErrorMessage ( "Unexpected response from the server." ) ;
66
- }
67
- }
68
- } ;
69
-
70
- return (
71
- < Dialog open = { open } onClose = { onClose } aria-labelledby = "form-dialog-title" >
72
- < DialogContent >
73
- < Box
74
- component = "form"
75
- noValidate
76
- sx = { {
77
- display : "flex" ,
78
- flexDirection : "column" ,
79
- alignItems : "center" ,
80
- padding : "24px" ,
81
- } }
82
- >
83
- < Avatar sx = { { bgcolor : "secondary.main" , marginBottom : 4 } } >
84
- < LockOutlinedIcon />
85
- </ Avatar >
86
- < Typography variant = "h5" align = "center" sx = { { marginBottom : 4 } } >
87
- Register Admin User
88
- </ Typography >
89
- < Box >
90
- { errorMessage && errorMessage != "" && (
91
- < Alert severity = "error" sx = { { marginBottom : 2 } } >
92
- { errorMessage }
93
- </ Alert >
94
- ) }
95
- </ Box >
96
- < TextField
97
- margin = "normal"
98
- error = { errors . username }
99
- helperText = { errors . username ? "Please enter a username" : " " }
100
- required
101
- fullWidth
102
- id = "register-username"
103
- label = "Username"
104
- name = "username"
105
- autoComplete = "username"
106
- autoFocus
107
- value = { username }
108
- onChange = { ( e ) => setUsername ( e . target . value ) }
109
- />
110
- < TextField
111
- margin = "normal"
112
- error = { errors . password }
113
- helperText = { errors . password ? "Please enter a password" : " " }
114
- required
115
- fullWidth
116
- name = "password"
117
- label = "Password"
118
- type = "password"
119
- id = "register-password"
120
- autoComplete = "new-password"
121
- value = { password }
122
- onChange = { ( e ) => setPassword ( e . target . value ) }
123
- />
124
- < TextField
125
- required
126
- fullWidth
127
- name = "confirm-password"
128
- label = "Confirm Password"
129
- type = "password"
130
- id = "confirm-password"
131
- error = { errors . confirmPasswordMatch }
132
- value = { confirmPassword }
133
- helperText = { errors . confirmPasswordMatch ? "Passwords do not match" : " " }
134
- onChange = { ( e ) => setConfirmPassword ( e . target . value ) }
135
- />
136
- < Box
137
- mt = { 1 }
138
- width = "100%"
139
- display = "flex"
140
- flexDirection = "column"
141
- alignItems = "center"
142
- justifyContent = "center"
143
- >
144
- < Button
145
- onClick = { handleRegister }
146
- type = "submit"
147
- fullWidth
148
- variant = "contained"
149
- sx = { { maxWidth : "120px" } }
150
- >
151
- Register
152
- </ Button >
153
- </ Box >
154
- </ Box >
155
- </ DialogContent >
156
- </ Dialog >
157
- ) ;
158
- }
159
-
9
+ import React from "react" ;
10
+ import { UserModal } from "@/app/user-management/components/UserCreateModal" ;
11
+ import type { UserModalProps } from "@/app/user-management/components/UserCreateModal" ;
12
+ const RegisterModal = ( props : Omit < UserModalProps , "fields" > ) => (
13
+ < UserModal
14
+ { ...props }
15
+ fields = { [ "username" , "password" , "confirmPassword" ] }
16
+ showCancel = { false }
17
+ />
18
+ ) ;
160
19
const AdminAlertModal = ( {
161
20
open,
162
21
onClose,
@@ -183,76 +42,4 @@ const AdminAlertModal = ({
183
42
) ;
184
43
} ;
185
44
186
- const ConfirmationModal = ( {
187
- open,
188
- onClose,
189
- recoveryCodes,
190
- } : {
191
- open : boolean ;
192
- onClose : ( ) => void ;
193
- recoveryCodes : string [ ] ;
194
- } ) => {
195
- const [ isClicked , setIsClicked ] = useState ( false ) ;
196
-
197
- const handleClose = ( ) => {
198
- setIsClicked ( false ) ;
199
- onClose ( ) ;
200
- } ;
201
-
202
- const handleCopyToClipboard = async ( ) => {
203
- try {
204
- await navigator . clipboard . writeText ( recoveryCodes . join ( "\n" ) ) ;
205
- } catch ( err ) {
206
- console . error ( "Failed to copy recovery codes: " , err ) ;
207
- }
208
- } ;
209
-
210
- return (
211
- < Dialog open = { open } onClose = { onClose } >
212
- < DialogTitle > Admin User Created</ DialogTitle >
213
- < DialogContent >
214
- < DialogContentText >
215
- The admin user has been successfully registered. Please save the recovery
216
- codes below. You will not be able to see them again.
217
- </ DialogContentText >
218
- < TextField
219
- fullWidth
220
- multiline
221
- margin = "normal"
222
- value = { recoveryCodes ? recoveryCodes . join ( "\n" ) : "" }
223
- InputProps = { {
224
- readOnly : true ,
225
- sx : {
226
- textAlign : "center" ,
227
- } ,
228
- } }
229
- inputProps = { {
230
- style : { textAlign : "center" } ,
231
- } }
232
- />
233
-
234
- < Box display = "flex" justifyContent = "center" mt = { 2 } >
235
- < Button
236
- variant = "contained"
237
- onClick = { ( ) => {
238
- handleCopyToClipboard ( ) ;
239
- setIsClicked ( true ) ;
240
- } }
241
- startIcon = { isClicked ? < CheckIcon /> : < ContentCopyIcon /> }
242
- style = { { paddingLeft : "20px" , paddingRight : "20px" } }
243
- >
244
- { isClicked ? "Copied" : "Copy" }
245
- </ Button >
246
- </ Box >
247
- </ DialogContent >
248
-
249
- < DialogActions sx = { { marginBottom : 1 , marginRight : 1 } } >
250
- < Button onClick = { handleClose } color = "primary" variant = "contained" autoFocus >
251
- Back to Login
252
- </ Button >
253
- </ DialogActions >
254
- </ Dialog >
255
- ) ;
256
- } ;
257
-
258
- export { AdminAlertModal , RegisterModal , ConfirmationModal } ;
45
+ export { AdminAlertModal , RegisterModal } ;
0 commit comments