// frontend/src/pages/Settings/Settings.tsx - UPDATED WITH VALIDATION STRATEGY import React, { useState, useEffect, useRef } from 'react'; import { useAuth } from '../../contexts/AuthContext'; import { employeeService } from '../../services/employeeService'; import { useNotification } from '../../contexts/NotificationContext'; import { useBackendValidation } from '../../hooks/useBackendValidation'; import AvailabilityManager from '../Employees/components/AvailabilityManager'; import { Employee } from '../../models/Employee'; import { styles } from './type/SettingsType'; const Settings: React.FC = () => { const { user: currentUser, updateUser } = useAuth(); const { showNotification } = useNotification(); const { executeWithValidation, clearErrors, isSubmitting } = useBackendValidation(); const [activeTab, setActiveTab] = useState<'profile' | 'password' | 'availability'>('profile'); const [showAvailabilityManager, setShowAvailabilityManager] = useState(false); // Profile form state const [profileForm, setProfileForm] = useState({ firstname: currentUser?.firstname || '', lastname: currentUser?.lastname || '' }); // Password form state const [passwordForm, setPasswordForm] = useState({ currentPassword: '', newPassword: '', 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({ firstname: currentUser.firstname || '', lastname: currentUser.lastname || '' }); } }, [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 => ({ ...prev, [name]: value })); }; const handlePasswordChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setPasswordForm(prev => ({ ...prev, [name]: value })); }; // Password visibility handlers const handleCurrentPasswordMouseDown = () => { currentPasswordTimeoutRef.current = setTimeout(() => { setShowCurrentPassword(true); }, 300); }; const handleCurrentPasswordMouseUp = () => { if (currentPasswordTimeoutRef.current) { clearTimeout(currentPasswordTimeoutRef.current); currentPasswordTimeoutRef.current = null; } setShowCurrentPassword(false); }; const handleNewPasswordMouseDown = () => { newPasswordTimeoutRef.current = setTimeout(() => { setShowNewPassword(true); }, 300); }; const handleNewPasswordMouseUp = () => { if (newPasswordTimeoutRef.current) { clearTimeout(newPasswordTimeoutRef.current); newPasswordTimeoutRef.current = null; } setShowNewPassword(false); }; 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(); }; const handleContextMenu = (e: React.MouseEvent) => { e.preventDefault(); }; const handleProfileUpdate = async (e: React.FormEvent) => { e.preventDefault(); if (!currentUser) return; // BASIC FRONTEND VALIDATION: Only check required fields if (!profileForm.firstname.trim()) { showNotification({ type: 'error', title: 'Fehler', message: 'Vorname ist erforderlich' }); return; } if (!profileForm.lastname.trim()) { showNotification({ type: 'error', title: 'Fehler', message: 'Nachname ist erforderlich' }); return; } try { // Use executeWithValidation to handle backend validation await executeWithValidation(async () => { const updatedEmployee = await employeeService.updateEmployee(currentUser.id, { firstname: profileForm.firstname.trim(), lastname: profileForm.lastname.trim() }); // Update the auth context with new user data updateUser(updatedEmployee); showNotification({ type: 'success', title: 'Erfolg', message: 'Profil erfolgreich aktualisiert' }); }); } catch (error) { // Backend validation errors are already handled by executeWithValidation // We only need to handle unexpected errors here console.error('Unexpected error:', error); } }; const handlePasswordUpdate = async (e: React.FormEvent) => { e.preventDefault(); if (!currentUser) return; // BASIC FRONTEND VALIDATION: Only check minimum requirements if (!passwordForm.currentPassword) { showNotification({ type: 'error', title: 'Fehler', message: 'Aktuelles Passwort ist erforderlich' }); return; } if (!passwordForm.newPassword) { showNotification({ type: 'error', title: 'Fehler', message: 'Neues Passwort ist erforderlich' }); return; } if (passwordForm.newPassword.length < 8) { showNotification({ type: 'error', title: 'Fehler', message: 'Das neue Passwort muss mindestens 8 Zeichen lang sein' }); return; } if (passwordForm.newPassword !== passwordForm.confirmPassword) { showNotification({ type: 'error', title: 'Fehler', message: 'Die Passwörter stimmen nicht überein' }); return; } try { // Use executeWithValidation to handle backend validation await executeWithValidation(async () => { await employeeService.changePassword(currentUser.id, { currentPassword: passwordForm.currentPassword, newPassword: passwordForm.newPassword, confirmPassword: passwordForm.confirmPassword }); showNotification({ type: 'success', title: 'Erfolg', message: 'Passwort erfolgreich geändert' }); // Clear password form setPasswordForm({ currentPassword: '', newPassword: '', confirmPassword: '' }); }); } catch (error) { // Backend validation errors are already handled by executeWithValidation console.error('Unexpected error:', error); } }; const handleAvailabilitySave = () => { setShowAvailabilityManager(false); showNotification({ type: 'success', title: 'Erfolg', message: 'Verfügbarkeit erfolgreich gespeichert' }); }; const handleAvailabilityCancel = () => { setShowAvailabilityManager(false); }; // Clear validation errors when switching tabs const handleTabChange = (tab: 'profile' | 'password' | 'availability') => { clearErrors(); setActiveTab(tab); }; if (!currentUser) { return
Nicht eingeloggt
; } if (showAvailabilityManager) { return ( ); } return (
{/* Left Sidebar with Tabs */}

Einstellungen

Verwalten Sie Ihre Kontoeinstellungen und Präferenzen
{/* Right Content Area */}
{/* Profile Tab */} {activeTab === 'profile' && ( <>

Profilinformationen

Verwalten Sie Ihre persönlichen Informationen und Kontaktdaten

{/* Read-only information */}

Systeminformationen

E-Mail wird automatisch aus Vor- und Nachname generiert

Persönliche Informationen

{/* Editable name fields */}
{ 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'; }} />
)} {/* Password Tab */} {activeTab === 'password' && ( <>

Passwort ändern

Aktualisieren Sie Ihr Passwort für erhöhte Sicherheit

{/* 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'; }} />
{/* 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'; }} />
Das Passwort muss mindestens 8 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'; }} />
)} {/* Availability Tab */} {activeTab === 'availability' && ( <>

Meine Verfügbarkeit

Legen Sie Ihre persönliche Verfügbarkeit für Schichtpläne fest

📅

Verfügbarkeit verwalten

Hier können Sie Ihre persönliche Verfügbarkeit für Schichtpläne festlegen. Legen Sie für jeden Tag und jede Schicht fest, ob Sie bevorzugt, möglicherweise oder nicht verfügbar sind.

)}
); }; export default Settings;