feat: Implement password change functionality with client-side validation, API integration, and UI feedback for loading, success, and errors.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { TwoFactorSettings } from './TwoFactorSettings';
|
||||
import api from '@/services/api';
|
||||
|
||||
interface PasswordSecurityFormProps {
|
||||
onSave?: (data: { currentPassword: string; newPassword: string }) => void;
|
||||
@@ -20,23 +21,81 @@ export function PasswordSecurityForm({ onSave }: PasswordSecurityFormProps) {
|
||||
confirm: false,
|
||||
});
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [success, setSuccess] = useState('');
|
||||
|
||||
const handleChange = (field: string, value: string) => {
|
||||
setFormData((prev) => ({ ...prev, [field]: value }));
|
||||
// Clear messages when user starts typing
|
||||
if (error) setError('');
|
||||
if (success) setSuccess('');
|
||||
};
|
||||
|
||||
const toggleShowPassword = (field: 'current' | 'new' | 'confirm') => {
|
||||
setShowPasswords((prev) => ({ ...prev, [field]: !prev[field] }));
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
if (formData.newPassword !== formData.confirmPassword) {
|
||||
alert('Passwords do not match');
|
||||
const validatePassword = (password: string): boolean => {
|
||||
// Minimum 8 characters with at least one uppercase, lowercase, and number
|
||||
const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;
|
||||
return regex.test(password);
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
setError('');
|
||||
setSuccess('');
|
||||
|
||||
// Validate fields
|
||||
if (!formData.currentPassword) {
|
||||
setError('Current password is required');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!formData.newPassword) {
|
||||
setError('New password is required');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validatePassword(formData.newPassword)) {
|
||||
setError('Password must be at least 8 characters with uppercase, lowercase, and number');
|
||||
return;
|
||||
}
|
||||
|
||||
if (formData.newPassword !== formData.confirmPassword) {
|
||||
setError('Passwords do not match');
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
await api.post('/auth/change-password', {
|
||||
currentPassword: formData.currentPassword,
|
||||
newPassword: formData.newPassword,
|
||||
});
|
||||
|
||||
setSuccess('Password changed successfully');
|
||||
setFormData({
|
||||
currentPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
});
|
||||
|
||||
// Call onSave callback if provided
|
||||
if (onSave) {
|
||||
onSave({ currentPassword: formData.currentPassword, newPassword: formData.newPassword });
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
const error = err as { response?: { data?: { message?: string | string[] } } };
|
||||
const message = error.response?.data?.message;
|
||||
if (Array.isArray(message)) {
|
||||
setError(message[0]);
|
||||
} else {
|
||||
console.log('Updating password');
|
||||
setError(message || 'Failed to change password. Please try again.');
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -53,6 +112,20 @@ export function PasswordSecurityForm({ onSave }: PasswordSecurityFormProps) {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Error Message */}
|
||||
{error && (
|
||||
<div className="mb-4 p-3 bg-red-50 border border-red-200 text-red-600 rounded-[10px] text-[13px] font-serif">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Success Message */}
|
||||
{success && (
|
||||
<div className="mb-4 p-3 bg-green-50 border border-green-200 text-green-600 rounded-[10px] text-[13px] font-serif">
|
||||
{success}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Form Fields */}
|
||||
<div className="space-y-6 max-w-md">
|
||||
{/* Current Password */}
|
||||
@@ -132,9 +205,10 @@ export function PasswordSecurityForm({ onSave }: PasswordSecurityFormProps) {
|
||||
<div className="mt-8">
|
||||
<button
|
||||
onClick={handleSave}
|
||||
className="px-8 py-3 bg-[#e58625] text-white rounded-[15px] font-fractul font-medium text-[14px] hover:bg-[#d47920] transition-colors"
|
||||
disabled={loading}
|
||||
className="px-8 py-3 bg-[#e58625] text-white rounded-[15px] font-fractul font-medium text-[14px] hover:bg-[#d47920] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
Update Password
|
||||
{loading ? 'Updating...' : 'Update Password'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user