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