diff --git a/frontend/src/components/AuthScreen.jsx b/frontend/src/components/AuthScreen.jsx
index 92db79b..aff1ef9 100644
--- a/frontend/src/components/AuthScreen.jsx
+++ b/frontend/src/components/AuthScreen.jsx
@@ -1,16 +1,26 @@
import React, { useState } from 'react';
import { Activity, Lock, Mail, ArrowRight, ShieldCheck, CheckCircle2, AlertCircle, Sun, Moon, Info } from 'lucide-react';
import { api } from '../api';
+import PasswordToggleButton from './PasswordToggleButton';
export default function AuthScreen({ onAuthSuccess, sessionExpired = false, currentTheme, onToggleTheme }) {
const [mode, setMode] = useState('login'); // 'login' | 'register'
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
+ const [showPassword, setShowPassword] = useState(false);
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(sessionExpired ? 'Your session has expired. Please sign in again.' : null);
const [successMsg, setSuccessMsg] = useState(null);
+ const switchMode = (newMode) => {
+ setMode(newMode);
+ setError(null);
+ setShowPassword(false);
+ setShowConfirmPassword(false);
+ };
+
const handleSubmit = async (e) => {
e.preventDefault();
setError(null);
@@ -97,14 +107,14 @@ export default function AuthScreen({ onAuthSuccess, sessionExpired = false, curr
@@ -155,15 +165,20 @@ export default function AuthScreen({ onAuthSuccess, sessionExpired = false, curr
setPassword(e.target.value)}
disabled={loading}
/>
+ setShowPassword((prev) => !prev)}
+ disabled={loading}
+ />
{mode === 'register' && (
At least 8 characters required.
@@ -179,15 +194,21 @@ export default function AuthScreen({ onAuthSuccess, sessionExpired = false, curr
setConfirmPassword(e.target.value)}
disabled={loading}
/>
+ setShowConfirmPassword((prev) => !prev)}
+ label="confirm password"
+ disabled={loading}
+ />
)}
@@ -210,7 +231,7 @@ export default function AuthScreen({ onAuthSuccess, sessionExpired = false, curr
@@ -221,7 +242,7 @@ export default function AuthScreen({ onAuthSuccess, sessionExpired = false, curr
diff --git a/frontend/src/components/PasswordToggleButton.jsx b/frontend/src/components/PasswordToggleButton.jsx
new file mode 100644
index 0000000..53d696c
--- /dev/null
+++ b/frontend/src/components/PasswordToggleButton.jsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { Eye, EyeOff } from 'lucide-react';
+
+export default function PasswordToggleButton({
+ isVisible,
+ onToggle,
+ disabled = false,
+ label = 'password',
+ size = 18,
+ className = '',
+}) {
+ const actionText = isVisible ? `Hide ${label}` : `Show ${label}`;
+
+ return (
+
+ );
+}
+
diff --git a/frontend/src/index.css b/frontend/src/index.css
index da32e56..9d85c2a 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -68,7 +68,9 @@
}
/* Base Resets */
-*, *::before, *::after {
+*,
+*::before,
+*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
@@ -657,15 +659,19 @@ body {
transform: translateX(-100%);
width: 240px !important;
}
+
.app-sidebar.mobile-open {
transform: translateX(0);
}
+
.app-main {
margin-left: 0 !important;
}
+
.kpi-grid {
grid-template-columns: 1fr;
}
+
.content-body {
padding: 16px;
}
@@ -677,7 +683,9 @@ body {
/* Keyframe for loading spinners */
@keyframes spin {
- to { transform: rotate(360deg); }
+ to {
+ transform: rotate(360deg);
+ }
}
.spin-anim {
@@ -815,6 +823,35 @@ body {
box-shadow: 0 0 0 3px rgba(34, 184, 176, 0.2);
}
+.auth-input.has-toggle {
+ padding-right: 42px;
+}
+
+.password-toggle-btn {
+ position: absolute;
+ right: 10px;
+ background: transparent;
+ border: none;
+ color: var(--text-subtle);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 6px;
+ border-radius: 6px;
+ transition: color 0.15s ease, background-color 0.15s ease;
+}
+
+.password-toggle-btn:hover:not(:disabled) {
+ color: var(--text-main);
+ background-color: rgba(120, 159, 180, 0.15);
+}
+
+.password-toggle-btn:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
.auth-submit-btn {
width: 100%;
padding: 13px;
@@ -1384,4 +1421,4 @@ body {
background: var(--bg-card-solid);
border: 1px solid var(--border-glass);
color: var(--text-main);
-}
+}
\ No newline at end of file