From ce1c6b08b156b8b5701ea8f656854eb7203dfd4a Mon Sep 17 00:00:00 2001 From: donpat1to Date: Thu, 23 Oct 2025 20:01:21 +0200 Subject: [PATCH] added password unvewiling and relative boxing --- frontend/src/pages/Settings/Settings.tsx | 255 ++++++++++++++---- .../src/pages/Settings/type/SettingsType.tsx | 41 ++- 2 files changed, 236 insertions(+), 60 deletions(-) diff --git a/frontend/src/pages/Settings/Settings.tsx b/frontend/src/pages/Settings/Settings.tsx index d9d7a03..f35bf60 100644 --- a/frontend/src/pages/Settings/Settings.tsx +++ b/frontend/src/pages/Settings/Settings.tsx @@ -1,5 +1,5 @@ -// frontend/src/pages/Settings/Settings.tsx -import React, { useState, useEffect } from 'react'; +// frontend/src/pages/Settings/Settings.tsx - UPDATED WITH NEW STYLES +import React, { useState, useEffect, useRef } from 'react'; import { useAuth } from '../../contexts/AuthContext'; import { employeeService } from '../../services/employeeService'; import { useNotification } from '../../contexts/NotificationContext'; @@ -27,6 +27,16 @@ const Settings: React.FC = () => { confirmPassword: '' }); + // Password visibility states + const [showCurrentPassword, setShowCurrentPassword] = useState(false); + const [showNewPassword, setShowNewPassword] = useState(false); + const [showConfirmPassword, setShowConfirmPassword] = useState(false); + + // Refs for timeout management + const currentPasswordTimeoutRef = useRef(null); + const newPasswordTimeoutRef = useRef(null); + const confirmPasswordTimeoutRef = useRef(null); + useEffect(() => { if (currentUser) { setProfileForm({ @@ -36,6 +46,17 @@ const Settings: React.FC = () => { } }, [currentUser]); + // Cleanup timeouts on unmount + useEffect(() => { + return () => { + [currentPasswordTimeoutRef, newPasswordTimeoutRef, confirmPasswordTimeoutRef].forEach(ref => { + if (ref.current) { + clearTimeout(ref.current); + } + }); + }; + }, []); + const handleProfileChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setProfileForm(prev => ({ @@ -52,6 +73,67 @@ const Settings: React.FC = () => { })); }; + // Password visibility handlers for current password + const handleCurrentPasswordMouseDown = () => { + currentPasswordTimeoutRef.current = setTimeout(() => { + setShowCurrentPassword(true); + }, 300); + }; + + const handleCurrentPasswordMouseUp = () => { + if (currentPasswordTimeoutRef.current) { + clearTimeout(currentPasswordTimeoutRef.current); + currentPasswordTimeoutRef.current = null; + } + setShowCurrentPassword(false); + }; + + // Password visibility handlers for new password + const handleNewPasswordMouseDown = () => { + newPasswordTimeoutRef.current = setTimeout(() => { + setShowNewPassword(true); + }, 300); + }; + + const handleNewPasswordMouseUp = () => { + if (newPasswordTimeoutRef.current) { + clearTimeout(newPasswordTimeoutRef.current); + newPasswordTimeoutRef.current = null; + } + setShowNewPassword(false); + }; + + // Password visibility handlers for confirm password + const handleConfirmPasswordMouseDown = () => { + confirmPasswordTimeoutRef.current = setTimeout(() => { + setShowConfirmPassword(true); + }, 300); + }; + + const handleConfirmPasswordMouseUp = () => { + if (confirmPasswordTimeoutRef.current) { + clearTimeout(confirmPasswordTimeoutRef.current); + confirmPasswordTimeoutRef.current = null; + } + setShowConfirmPassword(false); + }; + + // Touch event handlers + const handleTouchStart = (setter: () => void) => (e: React.TouchEvent) => { + e.preventDefault(); + setter(); + }; + + const handleTouchEnd = (cleanup: () => void) => (e: React.TouchEvent) => { + e.preventDefault(); + cleanup(); + }; + + // Prevent context menu + const handleContextMenu = (e: React.MouseEvent) => { + e.preventDefault(); + }; + const handleProfileUpdate = async (e: React.FormEvent) => { e.preventDefault(); if (!currentUser) return; @@ -180,11 +262,6 @@ const Settings: React.FC = () => { ); } - // Get full name for display - const getFullName = () => { - return `${currentUser.firstname || ''} ${currentUser.lastname || ''}`.trim(); - }; - return (
{/* Left Sidebar with Tabs */} @@ -443,77 +520,137 @@ const Settings: React.FC = () => {
+ {/* Current Password Field */}
- { - e.target.style.borderColor = '#1a1325'; - e.target.style.boxShadow = '0 0 0 3px rgba(26, 19, 37, 0.1)'; - }} - onBlur={(e) => { - e.target.style.borderColor = '#e8e8e8'; - e.target.style.boxShadow = 'none'; - }} - /> +
+ { + e.target.style.borderColor = '#1a1325'; + e.target.style.boxShadow = '0 0 0 3px rgba(26, 19, 37, 0.1)'; + }} + onBlur={(e) => { + e.target.style.borderColor = '#e8e8e8'; + e.target.style.boxShadow = 'none'; + }} + /> + +
+ {/* New Password Field */}
- { - e.target.style.borderColor = '#1a1325'; - e.target.style.boxShadow = '0 0 0 3px rgba(26, 19, 37, 0.1)'; - }} - onBlur={(e) => { - e.target.style.borderColor = '#e8e8e8'; - e.target.style.boxShadow = 'none'; - }} - /> +
+ { + e.target.style.borderColor = '#1a1325'; + e.target.style.boxShadow = '0 0 0 3px rgba(26, 19, 37, 0.1)'; + }} + onBlur={(e) => { + e.target.style.borderColor = '#e8e8e8'; + e.target.style.boxShadow = 'none'; + }} + /> + +
Das Passwort muss mindestens 6 Zeichen lang sein.
+ {/* Confirm Password Field */}
- { - e.target.style.borderColor = '#1a1325'; - e.target.style.boxShadow = '0 0 0 3px rgba(26, 19, 37, 0.1)'; - }} - onBlur={(e) => { - e.target.style.borderColor = '#e8e8e8'; - e.target.style.boxShadow = 'none'; - }} - /> +
+ { + e.target.style.borderColor = '#1a1325'; + e.target.style.boxShadow = '0 0 0 3px rgba(26, 19, 37, 0.1)'; + }} + onBlur={(e) => { + e.target.style.borderColor = '#e8e8e8'; + e.target.style.boxShadow = 'none'; + }} + /> + +
diff --git a/frontend/src/pages/Settings/type/SettingsType.tsx b/frontend/src/pages/Settings/type/SettingsType.tsx index 5fdb636..4f05acc 100644 --- a/frontend/src/pages/Settings/type/SettingsType.tsx +++ b/frontend/src/pages/Settings/type/SettingsType.tsx @@ -1,4 +1,5 @@ - export const styles = { +// frontend/src/pages/Settings/type/SettingsType.tsx - CORRECTED +export const styles = { container: { display: 'flex', minHeight: 'calc(100vh - 120px)', @@ -121,11 +122,17 @@ display: 'flex', flexDirection: 'column' as const, gap: '0.5rem', + width: '100%', }, fieldLabel: { fontSize: '0.9rem', fontWeight: 600, color: '#161718', + width: '100%', + }, + fieldInputContainer: { + position: 'relative' as const, + width: '100%', }, fieldInput: { padding: '0.875rem 1rem', @@ -135,6 +142,20 @@ background: '#FBFAF6', transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', color: '#161718', + width: '100%', + boxSizing: 'border-box' as const, + }, + fieldInputWithIcon: { + padding: '0.875rem 1rem', + border: '1.5px solid #e8e8e8', + borderRadius: '8px', + fontSize: '0.95rem', + background: '#FBFAF6', + transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', + color: '#161718', + width: '100%', + paddingRight: '40px', + boxSizing: 'border-box' as const, }, fieldInputDisabled: { padding: '0.875rem 1rem', @@ -144,11 +165,29 @@ background: 'rgba(26, 19, 37, 0.05)', color: '#666', cursor: 'not-allowed', + width: '100%', + boxSizing: 'border-box' as const, }, fieldHint: { fontSize: '0.8rem', color: '#888', marginTop: '0.25rem', + width: '100%', + }, + passwordToggleButton: { + position: 'absolute' as const, + right: '10px', + top: '50%', + transform: 'translateY(-50%)', + background: 'none', + border: 'none', + cursor: 'pointer', + padding: '5px', + borderRadius: '4px', + transition: 'background-color 0.2s', + userSelect: 'none' as const, + WebkitUserSelect: 'none' as const, + touchAction: 'manipulation' as const, }, actions: { display: 'flex',