@@ -13,21 +13,25 @@ import { Input } from "@/components/ui/input";
13
13
import { encrypt } from "@/utils/encryption" ;
14
14
import { useUser } from "@clerk/nextjs" ;
15
15
import { Loader2 } from "lucide-react" ;
16
- import { useState } from "react" ;
16
+ import { ChangeEvent , useState } from "react" ;
17
17
import toast from "react-hot-toast" ;
18
18
import { z } from "zod" ;
19
19
20
+ const initialPasswordItemState = {
21
+ name : "" ,
22
+ username : "" ,
23
+ website : "" ,
24
+ password : "" ,
25
+ } ;
26
+
20
27
export const CreatePasswordDialog = ( {
21
28
open,
22
29
onClose,
23
30
} : {
24
31
open : boolean ;
25
32
onClose : ( ) => void ;
26
33
} ) => {
27
- const [ name , setName ] = useState ( "" ) ;
28
- const [ username , setUsername ] = useState ( "" ) ;
29
- const [ website , setWebsite ] = useState ( "" ) ;
30
- const [ password , setPassword ] = useState ( "" ) ;
34
+ const [ passwordItem , setPasswordItem ] = useState ( initialPasswordItemState ) ;
31
35
const [ loading , setLoading ] = useState ( false ) ;
32
36
33
37
const { user : clerkuser } = useUser ( ) ;
@@ -53,41 +57,39 @@ export const CreatePasswordDialog = ({
53
57
54
58
const handleSave = async ( ) => {
55
59
setLoading ( true ) ;
56
-
57
- const formattedWebsite = website . startsWith ( "https://" )
58
- ? website
59
- : `https://${ website } ` ;
60
-
61
- const validationResult = passwordSchema . safeParse ( {
62
- name,
63
- username,
64
- website : formattedWebsite ,
65
- password,
66
- } ) ;
67
-
60
+
61
+ const validationResult = passwordSchema . safeParse ( passwordItem ) ;
62
+
68
63
if ( ! validationResult . success ) {
69
64
const errorMessage =
70
65
validationResult . error . errors [ 0 ] ?. message || "Validation failed" ;
71
66
toast . error ( errorMessage ) ;
72
67
setLoading ( false ) ;
73
68
return ;
74
69
}
75
-
70
+
76
71
try {
77
72
await createPasswordItem (
78
- encrypt ( username , clerkuser ) ,
79
- encrypt ( formattedWebsite , clerkuser ) ,
80
- encrypt ( password , clerkuser )
73
+ encrypt ( passwordItem . username , clerkuser ) ,
74
+ encrypt ( passwordItem . website , clerkuser ) ,
75
+ encrypt ( passwordItem . password , clerkuser )
81
76
) ;
82
77
toast . success ( "Password created" ) ;
78
+ setPasswordItem ( initialPasswordItemState ) ;
83
79
onClose ( ) ;
84
80
} catch ( error ) {
85
81
toast . error ( "Failed to create password" ) ;
86
82
} finally {
87
83
setLoading ( false ) ;
88
84
}
89
85
} ;
90
-
86
+
87
+ const handleChange = ( e : ChangeEvent < HTMLInputElement > ) => {
88
+ setPasswordItem ( ( prevState ) => ( {
89
+ ...prevState ,
90
+ [ e . target . name ] : e . target . value ,
91
+ } ) ) ;
92
+ } ;
91
93
92
94
return (
93
95
< Dialog open = { open } onOpenChange = { onClose } >
@@ -99,31 +101,33 @@ export const CreatePasswordDialog = ({
99
101
< div className = "relative" >
100
102
< Input
101
103
placeholder = "Name"
102
- value = { name }
103
- onChange = { ( e ) => setName ( e . target . value ) }
104
+ value = { passwordItem . name }
105
+ onChange = { handleChange }
104
106
maxLength = { 50 }
107
+ name = "name"
105
108
/>
106
109
< div
107
110
className = "pointer-events-none absolute inset-y-0 end-0 flex items-center justify-center pe-3 text-xs tabular-nums text-muted-foreground peer-disabled:opacity-50"
108
111
aria-live = "polite"
109
112
role = "status"
110
113
>
111
- { name . length } /50
114
+ { passwordItem . name . length } /50
112
115
</ div >
113
116
</ div >
114
117
< div className = "relative" >
115
118
< Input
116
119
placeholder = "Username"
117
- value = { username }
118
- onChange = { ( e ) => setUsername ( e . target . value ) }
120
+ value = { passwordItem . username }
121
+ onChange = { handleChange }
119
122
maxLength = { 30 }
123
+ name = "username"
120
124
/>
121
125
< div
122
126
className = "pointer-events-none absolute inset-y-0 end-0 flex items-center justify-center pe-3 text-xs tabular-nums text-muted-foreground peer-disabled:opacity-50"
123
127
aria-live = "polite"
124
128
role = "status"
125
129
>
126
- { username . length } / 30
130
+ { passwordItem . username . length } / 30
127
131
</ div >
128
132
</ div >
129
133
< div className = "flex relative rounded-lg" >
@@ -133,38 +137,40 @@ export const CreatePasswordDialog = ({
133
137
< Input
134
138
placeholder = "Website"
135
139
className = "-ms-px h-12 rounded-tl-none rounded-bl-none"
136
- value = { website }
137
- onChange = { ( e ) => setWebsite ( e . target . value ) }
140
+ value = { passwordItem . website }
141
+ onChange = { handleChange }
138
142
maxLength = { 50 }
143
+ name = "website"
139
144
/>
140
145
< div
141
146
className = "pointer-events-none absolute inset-y-0 end-0 flex items-center justify-center pe-3 text-xs tabular-nums text-muted-foreground peer-disabled:opacity-50"
142
147
aria-live = "polite"
143
148
role = "status"
144
149
>
145
- { website . length } /50
150
+ { passwordItem . website . length } /50
146
151
</ div >
147
152
</ div >
148
153
< div className = "relative" >
149
154
< Input
150
155
placeholder = "Password"
151
- value = { password }
152
- onChange = { ( e ) => setPassword ( e . target . value ) }
156
+ value = { passwordItem . password }
157
+ onChange = { handleChange }
153
158
type = "password"
154
159
maxLength = { 128 }
160
+ name = "password"
155
161
/>
156
162
< div
157
163
className = "pointer-events-none absolute inset-y-0 end-0 flex items-center justify-center pe-3 text-xs tabular-nums text-muted-foreground peer-disabled:opacity-50"
158
164
aria-live = "polite"
159
165
role = "status"
160
166
>
161
- { password . length } /128
167
+ { passwordItem . password . length } /128
162
168
</ div >
163
169
</ div >
164
170
</ div >
165
171
< DialogFooter >
166
172
< div className = "mt-4 flex justify-end gap-2" >
167
- < Button variant = "outline" onClick = { onClose } >
173
+ < Button variant = "outline" onClick = { ( ) => onClose ( ) } >
168
174
Cancel
169
175
</ Button >
170
176
< Button onClick = { handleSave } >
0 commit comments