1
- "use client"
1
+ "use client" ;
2
2
3
- import { createPasswordItem } from "@/app/actions" ;
4
- import { Button } from "@/components/ui/button" ;
5
- import { Dialog , DialogContent , DialogFooter , DialogHeader , DialogTitle } from "@/components/ui/dialog" ;
6
- import { Input } from "@/components/ui/input" ;
7
- import { encrypt } from "@/utils/encryption" ;
8
- import { useUser } from "@clerk/nextjs" ;
9
- import { Loader2 } from "lucide-react" ;
10
- import { useState } from "react" ;
3
+ import { createPasswordItem } from "@/app/actions" ;
4
+ import { Button } from "@/components/ui/button" ;
5
+ import {
6
+ Dialog ,
7
+ DialogContent ,
8
+ DialogFooter ,
9
+ DialogHeader ,
10
+ DialogTitle ,
11
+ } from "@/components/ui/dialog" ;
12
+ import { Input } from "@/components/ui/input" ;
13
+ import { encrypt } from "@/utils/encryption" ;
14
+ import { useUser } from "@clerk/nextjs" ;
15
+ import { Loader2 } from "lucide-react" ;
16
+ import { useState } from "react" ;
11
17
import toast from "react-hot-toast" ;
12
- import { z } from "zod" ;
18
+ import { z } from "zod" ;
13
19
14
20
export const CreatePasswordDialog = ( {
15
21
open,
@@ -38,34 +44,39 @@ export const CreatePasswordDialog = ({
38
44
website : z
39
45
. string ( )
40
46
. url ( "Invalid website URL" )
41
- . max ( 2048 , "Website URL is too long" ) ,
47
+ . max ( 50 , "Website URL is too long" ) ,
42
48
password : z
43
49
. string ( )
44
- . min ( 6 , "Password must be at least 6 characters long" )
50
+ . min ( 2 , "Password must be at least 2 characters long" )
45
51
. max ( 128 , "Password must be at most 128 characters" ) ,
46
52
} ) ;
47
53
48
54
const handleSave = async ( ) => {
49
55
setLoading ( true ) ;
56
+
57
+ const formattedWebsite = website . startsWith ( "https://" )
58
+ ? website
59
+ : `https://${ website } ` ;
60
+
50
61
const validationResult = passwordSchema . safeParse ( {
51
62
name,
52
63
username,
53
- website,
64
+ website : formattedWebsite ,
54
65
password,
55
66
} ) ;
56
-
67
+
57
68
if ( ! validationResult . success ) {
58
69
const errorMessage =
59
70
validationResult . error . errors [ 0 ] ?. message || "Validation failed" ;
60
71
toast . error ( errorMessage ) ;
61
72
setLoading ( false ) ;
62
73
return ;
63
74
}
64
-
75
+
65
76
try {
66
77
await createPasswordItem (
67
78
encrypt ( username , clerkuser ) ,
68
- encrypt ( website , clerkuser ) ,
79
+ encrypt ( formattedWebsite , clerkuser ) ,
69
80
encrypt ( password , clerkuser )
70
81
) ;
71
82
toast . success ( "Password created" ) ;
@@ -76,6 +87,7 @@ export const CreatePasswordDialog = ({
76
87
setLoading ( false ) ;
77
88
}
78
89
} ;
90
+
79
91
80
92
return (
81
93
< Dialog open = { open } onOpenChange = { onClose } >
@@ -91,7 +103,13 @@ export const CreatePasswordDialog = ({
91
103
onChange = { ( e ) => setName ( e . target . value ) }
92
104
maxLength = { 50 }
93
105
/>
94
- < div className = "mt-1 text-sm text-gray-500" > { name . length } / 50</ div >
106
+ < div
107
+ 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
+ aria-live = "polite"
109
+ role = "status"
110
+ >
111
+ { name . length } /50
112
+ </ div >
95
113
</ div >
96
114
< div className = "relative" >
97
115
< Input
@@ -100,19 +118,31 @@ export const CreatePasswordDialog = ({
100
118
onChange = { ( e ) => setUsername ( e . target . value ) }
101
119
maxLength = { 30 }
102
120
/>
103
- < div className = "mt-1 text-sm text-gray-500" >
104
- { username . length } / 30
121
+ < div
122
+ 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
+ aria-live = "polite"
124
+ role = "status"
125
+ >
126
+ { username . length } /30
105
127
</ div >
106
128
</ div >
107
- < div className = "relative" >
129
+ < div className = "flex relative rounded-lg" >
130
+ < span className = "-z-10 inline-flex items-center rounded-s-lg border border-input bg-background px-3 text-sm text-muted-foreground" >
131
+ https://
132
+ </ span >
108
133
< Input
109
134
placeholder = "Website"
135
+ className = "-ms-px h-12 rounded-tl-none rounded-bl-none"
110
136
value = { website }
111
137
onChange = { ( e ) => setWebsite ( e . target . value ) }
112
- maxLength = { 1024 }
138
+ maxLength = { 50 }
113
139
/>
114
- < div className = "mt-1 text-sm text-gray-500" >
115
- { website . length } / 1024
140
+ < div
141
+ 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
+ aria-live = "polite"
143
+ role = "status"
144
+ >
145
+ { website . length } /50
116
146
</ div >
117
147
</ div >
118
148
< div className = "relative" >
@@ -123,8 +153,12 @@ export const CreatePasswordDialog = ({
123
153
type = "password"
124
154
maxLength = { 128 }
125
155
/>
126
- < div className = " mt-1 text-sm text-gray-500" >
127
- { password . length } / 128
156
+ < div
157
+ 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
+ aria-live = "polite"
159
+ role = "status"
160
+ >
161
+ { password . length } /128
128
162
</ div >
129
163
</ div >
130
164
</ div >
0 commit comments