Skip to content

Commit a0750ba

Browse files
committed
refactor: Improve password validation UI in signup form
1 parent 31f5b9c commit a0750ba

File tree

1 file changed

+43
-32
lines changed

1 file changed

+43
-32
lines changed

client/src/components/Auth/user-auth-form-signup.tsx

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,14 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
3434
const [passwordRules, setPasswordRules] = useState<PasswordRules | null>(null);
3535
const [isPasswordValid, setIsPasswordValid] = useState<boolean>(false);
3636
const allRulesPassed = passwordRules && Object.values(passwordRules).every((passed) => passed === true);
37+
const [hasStartedTyping, setHasStartedTyping] = useState(false);
3738
const navigate = useNavigate();
3839

40+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
41+
setHasStartedTyping(true);
42+
handlePasswordChange(e);
43+
};
44+
3945
// Username availability check with debounce
4046
useEffect(() => {
4147
const checkUsernameAvailability = async () => {
@@ -234,6 +240,7 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
234240
<Label className="sr-only" htmlFor="password">
235241
Password
236242
</Label>
243+
237244
<div className="relative flex items-center">
238245
<Input
239246
id="password"
@@ -242,42 +249,46 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
242249
autoComplete="current-password"
243250
disabled={isLoading}
244251
value={password}
245-
onChange={handlePasswordChange}
246-
className="dark:bg-zinc-900 pr-10"
252+
onChange={handleInputChange}
253+
className="dark:bg-zinc-900 pr-10"
247254
required
248255
/>
249-
{allRulesPassed && (
250-
<HoverCard>
251-
<HoverCardTrigger asChild>
252-
<Check className="absolute right-3 text-green-500" />
253-
</HoverCardTrigger>
254-
<HoverCardContent className="text-green-500 text-sm bg-zinc-900">
255-
{passwordRules &&
256-
Object.entries(passwordRules).map(([rule, passed]) => (
257-
<p key={rule} className={passed ? "text-green-500" : "text-red-500"}>
258-
{passwordRuleMessages[rule as keyof typeof passwordRuleMessages]}
259-
</p>
260-
))}
261-
</HoverCardContent>
262-
</HoverCard>
263-
)}
264-
{!allRulesPassed && (
265-
<HoverCard>
266-
<HoverCardTrigger asChild>
267-
<X className="absolute right-3 text-red-500" />
268-
</HoverCardTrigger>
269-
<HoverCardContent className="text-red-500 text-sm bg-zinc-900">
270-
{passwordRules &&
271-
Object.entries(passwordRules).map(([rule, passed]) => (
272-
<p key={rule} className={passed ? "text-green-500" : "text-red-500"}>
273-
{passwordRuleMessages[rule as keyof typeof passwordRuleMessages]}
274-
</p>
275-
))}
276-
</HoverCardContent>
277-
</HoverCard>
256+
257+
{/* Show the validation only after user has started typing */}
258+
{hasStartedTyping && (
259+
<>
260+
{allRulesPassed ? (
261+
<HoverCard>
262+
<HoverCardTrigger asChild>
263+
<Check className="absolute right-3 text-green-500" />
264+
</HoverCardTrigger>
265+
<HoverCardContent className="text-green-500 text-sm bg-zinc-900">
266+
{passwordRules &&
267+
Object.entries(passwordRules).map(([rule, passed]) => (
268+
<p key={rule} className={passed ? "text-green-500" : "text-red-500"}>
269+
{passwordRuleMessages[rule as keyof typeof passwordRuleMessages]}
270+
</p>
271+
))}
272+
</HoverCardContent>
273+
</HoverCard>
274+
) : (
275+
<HoverCard>
276+
<HoverCardTrigger asChild>
277+
<X className="absolute right-3 text-red-500" />
278+
</HoverCardTrigger>
279+
<HoverCardContent className="text-red-500 text-sm bg-zinc-900">
280+
{passwordRules &&
281+
Object.entries(passwordRules).map(([rule, passed]) => (
282+
<p key={rule} className={passed ? "text-green-500" : "text-red-500"}>
283+
{passwordRuleMessages[rule as keyof typeof passwordRuleMessages]}
284+
</p>
285+
))}
286+
</HoverCardContent>
287+
</HoverCard>
288+
)}
289+
</>
278290
)}
279291
</div>
280-
281292
</div>
282293
<Button
283294
disabled={

0 commit comments

Comments
 (0)