feat: Implement password change functionality with client-side validation, API integration, and UI feedback for loading, success, and errors.

This commit is contained in:
pradeepkumar
2026-02-06 09:45:12 +05:30
parent 5eb0934570
commit c3eaacce93

View File

@@ -2,6 +2,7 @@
import { useState } from 'react'; import { useState } from 'react';
import { TwoFactorSettings } from './TwoFactorSettings'; import { TwoFactorSettings } from './TwoFactorSettings';
import api from '@/services/api';
interface PasswordSecurityFormProps { interface PasswordSecurityFormProps {
onSave?: (data: { currentPassword: string; newPassword: string }) => void; onSave?: (data: { currentPassword: string; newPassword: string }) => void;
@@ -20,23 +21,81 @@ export function PasswordSecurityForm({ onSave }: PasswordSecurityFormProps) {
confirm: false, confirm: false,
}); });
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const [success, setSuccess] = useState('');
const handleChange = (field: string, value: string) => { const handleChange = (field: string, value: string) => {
setFormData((prev) => ({ ...prev, [field]: value })); setFormData((prev) => ({ ...prev, [field]: value }));
// Clear messages when user starts typing
if (error) setError('');
if (success) setSuccess('');
}; };
const toggleShowPassword = (field: 'current' | 'new' | 'confirm') => { const toggleShowPassword = (field: 'current' | 'new' | 'confirm') => {
setShowPasswords((prev) => ({ ...prev, [field]: !prev[field] })); setShowPasswords((prev) => ({ ...prev, [field]: !prev[field] }));
}; };
const handleSave = () => { const validatePassword = (password: string): boolean => {
if (formData.newPassword !== formData.confirmPassword) { // Minimum 8 characters with at least one uppercase, lowercase, and number
alert('Passwords do not match'); 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; 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) { if (onSave) {
onSave({ currentPassword: formData.currentPassword, newPassword: formData.newPassword }); 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 { } 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> </p>
</div> </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 */} {/* Form Fields */}
<div className="space-y-6 max-w-md"> <div className="space-y-6 max-w-md">
{/* Current Password */} {/* Current Password */}
@@ -132,9 +205,10 @@ export function PasswordSecurityForm({ onSave }: PasswordSecurityFormProps) {
<div className="mt-8"> <div className="mt-8">
<button <button
onClick={handleSave} 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> </button>
</div> </div>
</div> </div>