Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 32 additions & 33 deletions src/components/Auth/SignIn.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { useNavigate } from 'react-router-dom';
import "../../styles/auth.css";

const isStrongPassword = (password) => {
// At least one lowercase, uppercase, digit, symbol, min 8 char
const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$/;
return regex.test(password);
};
Expand Down Expand Up @@ -35,7 +34,7 @@ const SignIn = ({ onAuthSuccess }) => {

if (!formData.password) newErrors.password = 'Password is required';
else if (!isStrongPassword(formData.password)) {
newErrors.password =
newErrors.password =
'Password must be at least 8 characters, include uppercase, lowercase, number, and symbol.';
}

Expand Down Expand Up @@ -81,39 +80,39 @@ const SignIn = ({ onAuthSuccess }) => {
required
/>
<Mail className="email-icon-right" />
{errors.email && (
<p className="mt-1 text-sm text-red-600">{errors.email}</p>
)}
<p className="error-message">{errors.email || ""}</p>
</div>

{/* PASSWORD INPUT */}
{/* PASSWORD INPUT (wrapped to keep icon anchored) */}
<div className="password-input-container">
<input
id="signin-password"
name="password"
type={showPassword ? "text" : "password"}
value={formData.password}
onChange={handleInputChange}
placeholder="Password"
className="login-password"
required
/>
<span
className="password-icon"
onClick={() => setShowPassword(!showPassword)}
role="button"
aria-label="Toggle password visibility"
tabIndex={0}
onKeyDown={(e) =>
e.key === 'Enter' && setShowPassword(!showPassword)
}
data-testid="password-toggle"
>
{showPassword ? <FaEyeSlash size={18} /> : <FaEye size={18} />}
</span>
{errors.password && (
<p className="mt-1 text-sm text-red-600">{errors.password}</p>
)}
<div className="password-field-wrapper">
<input
id="signin-password"
name="password"
type={showPassword ? "text" : "password"}
value={formData.password}
onChange={handleInputChange}
placeholder="Password"
className="login-password"
required
/>
<span
className="password-icon"
onClick={() => setShowPassword(!showPassword)}
role="button"
aria-label="Toggle password visibility"
tabIndex={0}
onKeyDown={(e) =>
e.key === 'Enter' && setShowPassword(!showPassword)
}
data-testid="password-toggle"
>
{showPassword ? <FaEyeSlash size={18} /> : <FaEye size={18} />}
</span>
</div>

{/* Error message placed outside the inner wrapper so it won't change wrapper height */}
<p className="error-message">{errors.password || ""}</p>
</div>

<button
Expand Down Expand Up @@ -151,4 +150,4 @@ const SignIn = ({ onAuthSuccess }) => {
);
};

export default SignIn;
export default SignIn;
120 changes: 58 additions & 62 deletions src/components/Auth/SignUp.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import React, { useState } from 'react';
import { FaEye, FaEyeSlash } from 'react-icons/fa';
import { Mail } from 'lucide-react'; // Retained as per your provided code
import { Mail } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import "../../styles/auth.css";

const isStrongPassword = (password) => {
// At least one lowercase, uppercase, digit, symbol, min 8 char
const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$/;
return regex.test(password);
};
Expand Down Expand Up @@ -96,9 +95,7 @@ const SignUp = ({ onAuthSuccess }) => {
className="login-email"
required
/>
{errors.name && (
<p className="mt-1 text-sm text-red-600">{errors.name}</p>
)}
<p className="error-message">{errors.name || ""}</p>
</div>

{/* EMAIL INPUT */}
Expand All @@ -114,71 +111,69 @@ const SignUp = ({ onAuthSuccess }) => {
required
/>
<Mail className="email-icon-right" />
{errors.email && (
<p className="mt-1 text-sm text-red-600">{errors.email}</p>
)}
<p className="error-message">{errors.email || ""}</p>
</div>

{/* PASSWORD INPUT */}
<div className="password-input-container">
<input
id="signup-password"
name="password"
type={showPassword ? "text" : "password"}
value={formData.password}
onChange={handleInputChange}
placeholder="Password"
className="login-password"
required
/>
<span
className="password-icon"
onClick={() => setShowPassword(!showPassword)}
role="button"
aria-label="Toggle password visibility"
tabIndex={0}
onKeyDown={(e) => { // Changed to explicit if statement
if (e.key === 'Enter') {
setShowPassword(!showPassword);
}
}}
>
{showPassword ? <FaEyeSlash size={18} /> : <FaEye size={18} />}
</span>
{errors.password && (
<p className="mt-1 text-sm text-red-600">{errors.password}</p>
)}
<div className="password-field-wrapper">
<input
id="signup-password"
name="password"
type={showPassword ? "text" : "password"}
value={formData.password}
onChange={handleInputChange}
placeholder="Password"
className="login-password"
required
/>
<span
className="password-icon"
onClick={() => setShowPassword(!showPassword)}
role="button"
aria-label="Toggle password visibility"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter') {
setShowPassword(!showPassword);
}
}}
>
{showPassword ? <FaEyeSlash size={18} /> : <FaEye size={18} />}
</span>
</div>
<p className="error-message">{errors.password || ""}</p>
</div>

{/* CONFIRM PASSWORD INPUT */}
<div className="password-input-container">
<input
id="signup-confirm-password"
name="confirmPassword"
type={showConfirmPassword ? "text" : "password"}
value={formData.confirmPassword}
onChange={handleInputChange}
placeholder="Confirm Password"
className="login-password"
required
/>
<span
className="password-icon"
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
role="button"
aria-label="Toggle confirm password visibility"
tabIndex={0}
onKeyDown={(e) => { // Changed to explicit if statement (Line 190 in original)
if (e.key === 'Enter') {
setShowConfirmPassword(!showConfirmPassword);
}
}}
>
{showConfirmPassword ? <FaEyeSlash size={18} /> : <FaEye size={18} />}
</span>
{errors.confirmPassword && (
<p className="mt-1 text-sm text-red-600">{errors.confirmPassword}</p>
)}
<div className="password-field-wrapper">
<input
id="signup-confirm-password"
name="confirmPassword"
type={showConfirmPassword ? "text" : "password"}
value={formData.confirmPassword}
onChange={handleInputChange}
placeholder="Confirm Password"
className="login-password"
required
/>
<span
className="password-icon"
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
role="button"
aria-label="Toggle confirm password visibility"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter') {
setShowConfirmPassword(!showConfirmPassword);
}
}}
>
{showConfirmPassword ? <FaEyeSlash size={18} /> : <FaEye size={18} />}
</span>
</div>
<p className="error-message">{errors.confirmPassword || ""}</p>
</div>

<button
Expand Down Expand Up @@ -210,3 +205,4 @@ const SignUp = ({ onAuthSuccess }) => {

export default SignUp;


68 changes: 29 additions & 39 deletions src/styles/auth.css
Original file line number Diff line number Diff line change
Expand Up @@ -65,79 +65,73 @@
width: 100%;
}

/* Right-aligned mail icon inside email input */
/* Inner wrapper for email input + icon */
.email-field-wrapper {
position: relative;
width: 100%;
}

.email-icon-right {
position: absolute;
top: 50%;
right: 0.75rem;
transform: translateY(-90%);
transform: translateY(-155%);
height: 18px;
width: 18px;
color: #888;
pointer-events: none;
}

/* Input adjusted to leave space for right-side icon */
.login-email {
padding-right: 2.5rem;
}

/* Container for password input and icon */
/* Password input container — stays aligned even with error messages */
.password-input-container {
position: relative;
width: 100%;
display: flex;
flex-direction: column;
}

/* Password input with right padding */
/* Password input with space for icon */
.login-password {
padding-right: 3rem;
}

/* --- Inserted snippet here --- */
/* Small icon inside password input (like email icon) */
.password-field-wrapper {
position: relative;
width: 100%;
/* ensure height equals the input's height so top:50% is stable */
display: block;
}

/* Visibility toggle icon — always vertically centered */
.password-icon {
position: absolute;
top: 50%;
right: 0.75rem;
transform: translateY(-90%);
transform: translateY(-85%);
color: #888;
cursor: pointer;
height: 18px;
width: 18px;
display: flex;
align-items: center;
justify-content: center;
z-index: 2;
}

.password-icon:hover {
color: #1e293b;
}
/* --- end snippet --- */

/* Password toggle icon button (if used anywhere) */
.password-toggle-icon-button {
position: absolute;
right: 0.75rem;
top: 50%;
transform: translateY(-70%);
background: none;
border: none;
padding: 0;
cursor: pointer;
color: #64748b;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.125rem;
}

.password-toggle-icon-button:hover {
color: #1e293b;
}

.password-toggle-icon-button:focus {
outline: none;
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.5);
/* Error message with fixed height so it doesn't push the icon */
.error-message {
min-height: 20px;
margin-top: 6px;
font-size: 0.85rem;
color: red;
}

/* Submit button */
Expand Down Expand Up @@ -196,8 +190,6 @@
text-decoration: underline;
}

/* Responsive Design */

/* Mobile (≤480px) */
@media (max-width: 480px) {
.auth-card {
Expand All @@ -216,12 +208,9 @@
padding: 0.6rem 0.8rem;
font-size: 0.9rem;
}
.password-input-container .login-password {
.login-password {
padding-right: 2.25rem;
}
.password-toggle-icon-button {
right: 0.6rem;
}
.auth-submit-button {
font-size: 1rem;
padding: 0.6rem 1rem;
Expand All @@ -247,3 +236,4 @@