Password updator for users / admin
This commit is contained in:
@@ -193,6 +193,34 @@ class AuthManager {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Change user password
|
||||
async changePassword(currentPassword, newPassword) {
|
||||
try {
|
||||
const response = await apiClient.post('/auth/change-password', {
|
||||
currentPassword,
|
||||
newPassword
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
return {
|
||||
success: true,
|
||||
message: response.message || 'Password changed successfully'
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
error: response.error || 'Failed to change password'
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Change password failed:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error.message || 'Failed to change password. Please try again.'
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create global auth manager instance
|
||||
|
||||
@@ -124,6 +124,22 @@ class UserDashboard {
|
||||
});
|
||||
}
|
||||
|
||||
// Password change form
|
||||
const passwordForm = document.getElementById('change-password-form');
|
||||
if (passwordForm) {
|
||||
passwordForm.addEventListener('submit', (e) => {
|
||||
this.handlePasswordChange(e);
|
||||
});
|
||||
}
|
||||
|
||||
// Cancel password change button
|
||||
const cancelPasswordBtn = document.getElementById('cancel-password-change');
|
||||
if (cancelPasswordBtn) {
|
||||
cancelPasswordBtn.addEventListener('click', () => {
|
||||
this.resetPasswordForm();
|
||||
});
|
||||
}
|
||||
|
||||
// Response filter changes
|
||||
const responseCampaignFilter = document.getElementById('responses-campaign-filter');
|
||||
const responseStatusFilter = document.getElementById('responses-status-filter');
|
||||
@@ -1356,6 +1372,176 @@ class UserDashboard {
|
||||
this.showMessage('Failed to create campaign: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// Password Change Methods
|
||||
async handlePasswordChange(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const currentPassword = document.getElementById('current-password').value;
|
||||
const newPassword = document.getElementById('new-password').value;
|
||||
const confirmPassword = document.getElementById('confirm-password').value;
|
||||
|
||||
// Client-side validation
|
||||
if (newPassword !== confirmPassword) {
|
||||
this.showPasswordMessage('New passwords do not match', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (newPassword.length < 8) {
|
||||
this.showPasswordMessage('Password must be at least 8 characters long', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentPassword === newPassword) {
|
||||
this.showPasswordMessage('New password must be different from current password', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Disable submit button
|
||||
const submitBtn = e.target.querySelector('button[type="submit"]');
|
||||
const originalText = submitBtn.textContent;
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Changing Password...';
|
||||
|
||||
const result = await this.authManager.changePassword(currentPassword, newPassword);
|
||||
|
||||
// Re-enable button
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = originalText;
|
||||
|
||||
if (result.success) {
|
||||
this.showPasswordMessage(result.message || 'Password changed successfully!', 'success');
|
||||
|
||||
// Show toast notification
|
||||
this.showToast('🎉 Password changed successfully! Your account is now more secure.', 'success');
|
||||
|
||||
// Visual feedback: briefly change button to success state
|
||||
submitBtn.style.transition = 'all 0.3s ease';
|
||||
submitBtn.style.backgroundColor = '#27ae60';
|
||||
submitBtn.textContent = '✓ Password Changed!';
|
||||
|
||||
// Reset button after 2 seconds, then clear form
|
||||
setTimeout(() => {
|
||||
submitBtn.style.backgroundColor = '';
|
||||
submitBtn.textContent = originalText;
|
||||
this.resetPasswordForm();
|
||||
}, 2000);
|
||||
} else {
|
||||
this.showPasswordMessage(result.error || 'Failed to change password', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Password change error:', error);
|
||||
this.showPasswordMessage('Failed to change password: ' + error.message, 'error');
|
||||
|
||||
// Re-enable button on error
|
||||
const submitBtn = e.target.querySelector('button[type="submit"]');
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Change Password';
|
||||
}
|
||||
}
|
||||
|
||||
resetPasswordForm() {
|
||||
const form = document.getElementById('change-password-form');
|
||||
if (form) {
|
||||
form.reset();
|
||||
}
|
||||
|
||||
// Clear any messages
|
||||
const messageContainer = document.getElementById('password-message');
|
||||
if (messageContainer) {
|
||||
messageContainer.textContent = '';
|
||||
messageContainer.className = 'hidden';
|
||||
}
|
||||
}
|
||||
|
||||
showPasswordMessage(message, type) {
|
||||
const messageContainer = document.getElementById('password-message');
|
||||
if (messageContainer) {
|
||||
// Clear previous content
|
||||
messageContainer.innerHTML = '';
|
||||
|
||||
if (type === 'success') {
|
||||
// Add checkmark icon for success
|
||||
const checkmark = document.createElement('span');
|
||||
checkmark.className = 'success-checkmark';
|
||||
checkmark.textContent = '✓';
|
||||
messageContainer.appendChild(checkmark);
|
||||
|
||||
// Add message text
|
||||
const messageText = document.createElement('span');
|
||||
messageText.textContent = message;
|
||||
messageContainer.appendChild(messageText);
|
||||
|
||||
messageContainer.className = 'message-success password-success-animation';
|
||||
|
||||
// Add animation to the password form section
|
||||
const passwordSection = document.getElementById('change-password-form').parentElement;
|
||||
if (passwordSection) {
|
||||
passwordSection.style.transition = 'all 0.3s ease';
|
||||
passwordSection.style.borderColor = '#27ae60';
|
||||
passwordSection.style.boxShadow = '0 0 20px rgba(39, 174, 96, 0.3)';
|
||||
|
||||
// Reset the border after animation
|
||||
setTimeout(() => {
|
||||
passwordSection.style.borderColor = '';
|
||||
passwordSection.style.boxShadow = '';
|
||||
}, 2000);
|
||||
}
|
||||
} else {
|
||||
// Error message without checkmark
|
||||
messageContainer.textContent = message;
|
||||
messageContainer.className = 'message-error';
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-hide success messages after 5 seconds
|
||||
if (type === 'success') {
|
||||
setTimeout(() => {
|
||||
if (messageContainer) {
|
||||
messageContainer.style.transition = 'opacity 0.5s ease';
|
||||
messageContainer.style.opacity = '0';
|
||||
|
||||
setTimeout(() => {
|
||||
messageContainer.className = 'hidden';
|
||||
messageContainer.style.opacity = '1';
|
||||
}, 500);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
showToast(message, type = 'success') {
|
||||
// Create toast element
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast-notification ${type === 'error' ? 'error' : ''}`;
|
||||
|
||||
// Create icon
|
||||
const icon = document.createElement('div');
|
||||
icon.className = 'toast-icon';
|
||||
icon.textContent = type === 'success' ? '✓' : '✕';
|
||||
|
||||
// Create message text
|
||||
const messageText = document.createElement('span');
|
||||
messageText.textContent = message;
|
||||
|
||||
// Assemble toast
|
||||
toast.appendChild(icon);
|
||||
toast.appendChild(messageText);
|
||||
|
||||
// Add to page
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// Auto-remove after 4 seconds with animation
|
||||
setTimeout(() => {
|
||||
toast.classList.add('toast-exit');
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.parentNode.removeChild(toast);
|
||||
}
|
||||
}, 400); // Match animation duration
|
||||
}, 4000);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize dashboard when DOM is loaded
|
||||
|
||||
Reference in New Issue
Block a user