|
@@ -4,274 +4,7 @@
|
|
|
<meta charset="UTF-8">
|
|
<meta charset="UTF-8">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
<title>Auth Service</title>
|
|
<title>Auth Service</title>
|
|
|
- <style>
|
|
|
|
|
- * {
|
|
|
|
|
- margin: 0;
|
|
|
|
|
- padding: 0;
|
|
|
|
|
- box-sizing: border-box;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- body {
|
|
|
|
|
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
|
|
|
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
|
|
- min-height: 100vh;
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: center;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .container {
|
|
|
|
|
- background: white;
|
|
|
|
|
- border-radius: 15px;
|
|
|
|
|
- box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1);
|
|
|
|
|
- overflow: hidden;
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- max-width: 400px;
|
|
|
|
|
- margin: 20px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .header {
|
|
|
|
|
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
|
|
- color: white;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- padding: 30px 20px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .header h1 {
|
|
|
|
|
- font-size: 1.8rem;
|
|
|
|
|
- margin-bottom: 10px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .header p {
|
|
|
|
|
- opacity: 0.9;
|
|
|
|
|
- font-size: 0.9rem;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .tab-container {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- background: #f8f9fa;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .tab {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- padding: 15px;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- color: #666;
|
|
|
|
|
- border-bottom: 3px solid transparent;
|
|
|
|
|
- transition: all 0.3s ease;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .tab.active {
|
|
|
|
|
- color: #667eea;
|
|
|
|
|
- border-bottom-color: #667eea;
|
|
|
|
|
- background: white;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .form-container {
|
|
|
|
|
- padding: 40px 30px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .form {
|
|
|
|
|
- display: none;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .form.active {
|
|
|
|
|
- display: block;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .form-group {
|
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .form-group label {
|
|
|
|
|
- display: block;
|
|
|
|
|
- margin-bottom: 8px;
|
|
|
|
|
- color: #333;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .form-group input {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- padding: 12px 15px;
|
|
|
|
|
- border: 2px solid #e1e5e9;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- font-size: 1rem;
|
|
|
|
|
- transition: all 0.3s ease;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .form-group input:focus {
|
|
|
|
|
- outline: none;
|
|
|
|
|
- border-color: #667eea;
|
|
|
|
|
- box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .submit-btn {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- padding: 12px;
|
|
|
|
|
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
|
|
- color: white;
|
|
|
|
|
- border: none;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- font-size: 1rem;
|
|
|
|
|
- font-weight: 600;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- transition: all 0.3s ease;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .submit-btn:hover {
|
|
|
|
|
- transform: translateY(-2px);
|
|
|
|
|
- box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .submit-btn:disabled {
|
|
|
|
|
- background: #ccc;
|
|
|
|
|
- cursor: not-allowed;
|
|
|
|
|
- transform: none;
|
|
|
|
|
- box-shadow: none;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .message {
|
|
|
|
|
- margin-top: 15px;
|
|
|
|
|
- padding: 10px;
|
|
|
|
|
- border-radius: 5px;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .message.success {
|
|
|
|
|
- background: #d4edda;
|
|
|
|
|
- color: #155724;
|
|
|
|
|
- border: 1px solid #c3e6cb;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .message.error {
|
|
|
|
|
- background: #f8d7da;
|
|
|
|
|
- color: #721c24;
|
|
|
|
|
- border: 1px solid #f5c6cb;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .user-info {
|
|
|
|
|
- display: none;
|
|
|
|
|
- padding: 20px;
|
|
|
|
|
- background: #f8f9fa;
|
|
|
|
|
- border-top: 1px solid #e1e5e9;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .user-info.active {
|
|
|
|
|
- display: block;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .user-details {
|
|
|
|
|
- background: white;
|
|
|
|
|
- padding: 15px;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .user-details h3 {
|
|
|
|
|
- color: #333;
|
|
|
|
|
- margin-bottom: 10px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .user-details p {
|
|
|
|
|
- margin: 5px 0;
|
|
|
|
|
- color: #666;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .change-password-section {
|
|
|
|
|
- background: white;
|
|
|
|
|
- padding: 20px;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .change-password-section h3 {
|
|
|
|
|
- color: #333;
|
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
|
- font-size: 1.1rem;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .action-buttons {
|
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .action-btn {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- padding: 12px;
|
|
|
|
|
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
|
|
- color: white;
|
|
|
|
|
- border: none;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- font-size: 0.95rem;
|
|
|
|
|
- font-weight: 500;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- transition: all 0.3s ease;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .action-btn:hover {
|
|
|
|
|
- transform: translateY(-1px);
|
|
|
|
|
- box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .form-buttons {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- gap: 10px;
|
|
|
|
|
- margin-top: 15px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .form-buttons .submit-btn {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- margin: 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .logout-btn {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- padding: 10px;
|
|
|
|
|
- background: #dc3545;
|
|
|
|
|
- color: white;
|
|
|
|
|
- border: none;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- font-size: 0.9rem;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- transition: all 0.3s ease;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .logout-btn:hover {
|
|
|
|
|
- background: #c82333;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .loading {
|
|
|
|
|
- display: inline-block;
|
|
|
|
|
- width: 16px;
|
|
|
|
|
- height: 16px;
|
|
|
|
|
- border: 2px solid #ffffff;
|
|
|
|
|
- border-radius: 50%;
|
|
|
|
|
- border-top-color: transparent;
|
|
|
|
|
- animation: spin 1s ease-in-out infinite;
|
|
|
|
|
- margin-right: 8px;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @keyframes spin {
|
|
|
|
|
- to { transform: rotate(360deg); }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .profile-section, .security-section {
|
|
|
|
|
- margin-bottom: 25px;
|
|
|
|
|
- padding: 15px;
|
|
|
|
|
- background: #f8f9fa;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- border-left: 3px solid #667eea;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- .profile-section h4, .security-section h4 {
|
|
|
|
|
- margin: 0 0 15px 0;
|
|
|
|
|
- color: #333;
|
|
|
|
|
- font-size: 1rem;
|
|
|
|
|
- font-weight: 600;
|
|
|
|
|
- }
|
|
|
|
|
- </style>
|
|
|
|
|
|
|
+ <link rel="stylesheet" href="css/main.css">
|
|
|
</head>
|
|
</head>
|
|
|
<body>
|
|
<body>
|
|
|
<div class="container">
|
|
<div class="container">
|
|
@@ -397,407 +130,6 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <script>
|
|
|
|
|
- const API_BASE_URL = '/api';
|
|
|
|
|
- let currentUser = null;
|
|
|
|
|
- let resetToken = null;
|
|
|
|
|
-
|
|
|
|
|
- function parseURLParams() {
|
|
|
|
|
- const urlParams = new URLSearchParams(window.location.search);
|
|
|
|
|
- const hasResetFlag = urlParams.has('reset-password');
|
|
|
|
|
- const token = urlParams.get('token');
|
|
|
|
|
-
|
|
|
|
|
- return {
|
|
|
|
|
- isResetMode: hasResetFlag && token,
|
|
|
|
|
- resetToken: token
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
- const urlInfo = parseURLParams();
|
|
|
|
|
-
|
|
|
|
|
- if (urlInfo.isResetMode) {
|
|
|
|
|
- resetToken = urlInfo.resetToken;
|
|
|
|
|
- showResetPasswordSection();
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const token = localStorage.getItem('authToken');
|
|
|
|
|
- const userData = localStorage.getItem('userData');
|
|
|
|
|
-
|
|
|
|
|
- if (token && userData) {
|
|
|
|
|
- try {
|
|
|
|
|
- currentUser = JSON.parse(userData);
|
|
|
|
|
- showUserSection();
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- console.error('Invalid user data in localStorage', e);
|
|
|
|
|
- localStorage.removeItem('authToken');
|
|
|
|
|
- localStorage.removeItem('userData');
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- function switchTab(tab) {
|
|
|
|
|
- document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
|
|
|
|
- document.querySelector(`.tab:nth-child(${tab === 'login' ? '1' : '2'})`).classList.add('active');
|
|
|
|
|
-
|
|
|
|
|
- document.querySelectorAll('.form').forEach(f => f.classList.remove('active'));
|
|
|
|
|
- document.getElementById(tab + 'Form').classList.add('active');
|
|
|
|
|
-
|
|
|
|
|
- clearMessages();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function clearMessages() {
|
|
|
|
|
- document.querySelectorAll('.message').forEach(msg => {
|
|
|
|
|
- msg.style.display = 'none';
|
|
|
|
|
- msg.textContent = '';
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function showMessage(elementId, message, type) {
|
|
|
|
|
- const element = document.getElementById(elementId);
|
|
|
|
|
- element.textContent = message;
|
|
|
|
|
- element.className = `message ${type}`;
|
|
|
|
|
- element.style.display = 'block';
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function setButtonLoading(buttonId, loading) {
|
|
|
|
|
- const button = document.getElementById(buttonId);
|
|
|
|
|
- if (loading) {
|
|
|
|
|
- button.innerHTML = '<span class="loading"></span>Processing...';
|
|
|
|
|
- button.disabled = true;
|
|
|
|
|
- } else {
|
|
|
|
|
- if (buttonId.includes('login')) {
|
|
|
|
|
- button.innerHTML = 'Sign In';
|
|
|
|
|
- } else if (buttonId.includes('register')) {
|
|
|
|
|
- button.innerHTML = 'Create Account';
|
|
|
|
|
- } else if (buttonId.includes('editProfile')) {
|
|
|
|
|
- button.innerHTML = 'Update Profile';
|
|
|
|
|
- } else if (buttonId.includes('resetPassword')) {
|
|
|
|
|
- button.innerHTML = 'Reset Password';
|
|
|
|
|
- }
|
|
|
|
|
- button.disabled = false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- document.getElementById('loginForm').addEventListener('submit', async function(e) {
|
|
|
|
|
- e.preventDefault();
|
|
|
|
|
-
|
|
|
|
|
- const username = document.getElementById('loginUsername').value;
|
|
|
|
|
- const password = document.getElementById('loginPassword').value;
|
|
|
|
|
-
|
|
|
|
|
- setButtonLoading('loginBtn', true);
|
|
|
|
|
- clearMessages();
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const response = await fetch(`${API_BASE_URL}/authenticate`, {
|
|
|
|
|
- method: 'POST',
|
|
|
|
|
- headers: {
|
|
|
|
|
- 'Content-Type': 'application/json'
|
|
|
|
|
- },
|
|
|
|
|
- body: JSON.stringify({ username, password })
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- if (response.ok) {
|
|
|
|
|
- const data = await response.json();
|
|
|
|
|
-
|
|
|
|
|
- localStorage.setItem('authToken', data.token);
|
|
|
|
|
- localStorage.setItem('userData', JSON.stringify(data));
|
|
|
|
|
-
|
|
|
|
|
- currentUser = data;
|
|
|
|
|
- setButtonLoading('loginBtn', false);
|
|
|
|
|
- showUserSection();
|
|
|
|
|
- } else {
|
|
|
|
|
- const errorText = await response.text();
|
|
|
|
|
- showMessage('loginMessage', errorText || 'Login failed. Please check your credentials.', 'error');
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('Login error:', error);
|
|
|
|
|
- showMessage('loginMessage', 'Network error. Please check if the auth service is running.', 'error');
|
|
|
|
|
- } finally {
|
|
|
|
|
- setButtonLoading('loginBtn', false);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- document.getElementById('registerForm').addEventListener('submit', async function(e) {
|
|
|
|
|
- e.preventDefault();
|
|
|
|
|
-
|
|
|
|
|
- const username = document.getElementById('registerUsername').value;
|
|
|
|
|
- const password = document.getElementById('registerPassword').value;
|
|
|
|
|
- const email = document.getElementById('registerEmail').value;
|
|
|
|
|
-
|
|
|
|
|
- setButtonLoading('registerBtn', true);
|
|
|
|
|
- clearMessages();
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const response = await fetch(`${API_BASE_URL}/register`, {
|
|
|
|
|
- method: 'POST',
|
|
|
|
|
- headers: {
|
|
|
|
|
- 'Content-Type': 'application/json'
|
|
|
|
|
- },
|
|
|
|
|
- body: JSON.stringify({ username, email, password })
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- if (response.ok) {
|
|
|
|
|
- const data = await response.json();
|
|
|
|
|
-
|
|
|
|
|
- localStorage.setItem('authToken', data.token);
|
|
|
|
|
- localStorage.setItem('userData', JSON.stringify(data));
|
|
|
|
|
-
|
|
|
|
|
- currentUser = data;
|
|
|
|
|
- setButtonLoading('registerBtn', false);
|
|
|
|
|
- showUserSection();
|
|
|
|
|
- } else {
|
|
|
|
|
- const errorText = await response.text();
|
|
|
|
|
- showMessage('registerMessage', errorText || 'Registration failed. Please try again.', 'error');
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('Registration error:', error);
|
|
|
|
|
- showMessage('registerMessage', 'Network error. Please check if the auth service is running.', 'error');
|
|
|
|
|
- } finally {
|
|
|
|
|
- setButtonLoading('registerBtn', false);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- document.getElementById('resetPasswordForm').addEventListener('submit', async function(e) {
|
|
|
|
|
- e.preventDefault();
|
|
|
|
|
-
|
|
|
|
|
- const newPassword = document.getElementById('resetNewPassword').value;
|
|
|
|
|
- const confirmPassword = document.getElementById('resetConfirmPassword').value;
|
|
|
|
|
-
|
|
|
|
|
- if (newPassword !== confirmPassword) {
|
|
|
|
|
- showMessage('resetPasswordMessage', 'New passwords do not match.', 'error');
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (newPassword.length < 4) {
|
|
|
|
|
- showMessage('resetPasswordMessage', 'New password must be at least 4 characters long.', 'error');
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- setButtonLoading('resetPasswordBtn', true);
|
|
|
|
|
- clearResetPasswordMessages();
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const response = await fetch(`${API_BASE_URL}/users/reset-password`, {
|
|
|
|
|
- method: 'POST',
|
|
|
|
|
- headers: {
|
|
|
|
|
- 'Content-Type': 'application/json',
|
|
|
|
|
- 'Authorization': 'Bearer ' + resetToken
|
|
|
|
|
- },
|
|
|
|
|
- body: JSON.stringify({
|
|
|
|
|
- newPassword: newPassword
|
|
|
|
|
- })
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- if (response.ok) {
|
|
|
|
|
- showMessage('resetPasswordMessage', 'Password reset successfully!', 'success');
|
|
|
|
|
-
|
|
|
|
|
- document.getElementById('resetPasswordForm').reset();
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- window.location.href = window.location.pathname;
|
|
|
|
|
- }, 1000);
|
|
|
|
|
- } else {
|
|
|
|
|
- const errorText = await response.text();
|
|
|
|
|
- showMessage('resetPasswordMessage', errorText || 'Failed to reset password. Please try again.', 'error');
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('Reset password error:', error);
|
|
|
|
|
- showMessage('resetPasswordMessage', 'Network error. Please check if the auth service is running.', 'error');
|
|
|
|
|
- } finally {
|
|
|
|
|
- setButtonLoading('resetPasswordBtn', false);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- document.getElementById('editProfileForm').addEventListener('submit', async function(e) {
|
|
|
|
|
- e.preventDefault();
|
|
|
|
|
-
|
|
|
|
|
- const currentPassword = document.getElementById('currentPassword').value;
|
|
|
|
|
- const newPassword = document.getElementById('newPassword').value;
|
|
|
|
|
- const confirmPassword = document.getElementById('confirmPassword').value;
|
|
|
|
|
- const email = document.getElementById('editEmail').value;
|
|
|
|
|
-
|
|
|
|
|
- // Validate that at least one field is being updated
|
|
|
|
|
- const isPasswordChange = newPassword.trim() !== '';
|
|
|
|
|
- const currentEmail = currentUser.email || '';
|
|
|
|
|
- const newEmail = email.trim();
|
|
|
|
|
- const isEmailChange = newEmail !== currentEmail;
|
|
|
|
|
-
|
|
|
|
|
- if (!isPasswordChange && !isEmailChange) {
|
|
|
|
|
- showMessage('editProfileMessage', 'Please make at least one change: update your email address or change your password.', 'error');
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (isPasswordChange && newPassword !== confirmPassword) {
|
|
|
|
|
- showMessage('editProfileMessage', 'New passwords do not match.', 'error');
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (isPasswordChange && newPassword.length < 4) {
|
|
|
|
|
- showMessage('editProfileMessage', 'New password must be at least 4 characters long.', 'error');
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- setButtonLoading('editProfileBtn', true);
|
|
|
|
|
- clearEditProfileMessages();
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const requestBody = { currentPassword };
|
|
|
|
|
-
|
|
|
|
|
- if (isPasswordChange) {
|
|
|
|
|
- requestBody.newPassword = newPassword;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (isEmailChange) {
|
|
|
|
|
- requestBody.email = newEmail;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const response = await fetch(`${API_BASE_URL}/users/update-profile`, {
|
|
|
|
|
- method: 'POST',
|
|
|
|
|
- headers: {
|
|
|
|
|
- 'Content-Type': 'application/json',
|
|
|
|
|
- 'Authorization': `Bearer ${localStorage.getItem('authToken')}`
|
|
|
|
|
- },
|
|
|
|
|
- body: JSON.stringify(requestBody)
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- if (response.ok) {
|
|
|
|
|
- const data = await response.json();
|
|
|
|
|
-
|
|
|
|
|
- let message = '';
|
|
|
|
|
- if (isPasswordChange && isEmailChange) {
|
|
|
|
|
- message = 'Email and password updated successfully! Please log in with your new password.';
|
|
|
|
|
- document.getElementById('editProfileForm').reset();
|
|
|
|
|
- setTimeout(() => logout(), 1500);
|
|
|
|
|
- } else if (isPasswordChange) {
|
|
|
|
|
- message = 'Password updated successfully! Please log in with your new password.';
|
|
|
|
|
- document.getElementById('editProfileForm').reset();
|
|
|
|
|
- setTimeout(() => logout(), 1500);
|
|
|
|
|
- } else if (isEmailChange) {
|
|
|
|
|
- message = 'Email updated successfully!';
|
|
|
|
|
- // Update the stored user data with new email
|
|
|
|
|
- currentUser.email = newEmail;
|
|
|
|
|
- localStorage.setItem('userData', JSON.stringify(currentUser));
|
|
|
|
|
- updateUserDisplay(); // Refresh the displayed email
|
|
|
|
|
- document.getElementById('editProfileForm').reset();
|
|
|
|
|
- setTimeout(() => hideEditProfileForm(), 1000);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- showMessage('editProfileMessage', message, 'success');
|
|
|
|
|
- } else {
|
|
|
|
|
- const errorText = await response.text();
|
|
|
|
|
- showMessage('editProfileMessage', errorText || 'Failed to update profile. Please try again.', 'error');
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error('Update profile error:', error);
|
|
|
|
|
- showMessage('editProfileMessage', 'Network error. Please check if the auth service is running.', 'error');
|
|
|
|
|
- } finally {
|
|
|
|
|
- setButtonLoading('editProfileBtn', false);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- function clearEditProfileMessages() {
|
|
|
|
|
- const messageElement = document.getElementById('editProfileMessage');
|
|
|
|
|
- messageElement.style.display = 'none';
|
|
|
|
|
- messageElement.textContent = '';
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function clearResetPasswordMessages() {
|
|
|
|
|
- const messageElement = document.getElementById('resetPasswordMessage');
|
|
|
|
|
- messageElement.style.display = 'none';
|
|
|
|
|
- messageElement.textContent = '';
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function updateUserDisplay() {
|
|
|
|
|
- document.getElementById('currentUsername').textContent = currentUser.username;
|
|
|
|
|
- document.getElementById('currentEmail').textContent = currentUser.email || '-';
|
|
|
|
|
- document.getElementById('currentUserId').textContent = maskUserId(currentUser.id);
|
|
|
|
|
- document.getElementById('currentRoles').textContent = currentUser.roles.join(', ');
|
|
|
|
|
-
|
|
|
|
|
- const expirationDate = new Date(currentUser.expirationDate);
|
|
|
|
|
- document.getElementById('tokenExpiration').textContent = expirationDate.toLocaleString();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function showUserSection() {
|
|
|
|
|
- document.getElementById('authSection').style.display = 'none';
|
|
|
|
|
- document.getElementById('userSection').classList.add('active');
|
|
|
|
|
- updateUserDisplay();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function showResetPasswordSection() {
|
|
|
|
|
- document.getElementById('authSection').style.display = 'none';
|
|
|
|
|
- document.getElementById('userSection').classList.remove('active');
|
|
|
|
|
- document.getElementById('resetPasswordSection').style.display = 'block';
|
|
|
|
|
-
|
|
|
|
|
- // Focus on the first input field
|
|
|
|
|
- document.getElementById('resetNewPassword').focus();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function maskUserId(id) {
|
|
|
|
|
- const parts = id.split("-");
|
|
|
|
|
- return parts[0] + "-****-" + parts[4];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function logout() {
|
|
|
|
|
- localStorage.removeItem('authToken');
|
|
|
|
|
- localStorage.removeItem('userData');
|
|
|
|
|
- currentUser = null;
|
|
|
|
|
-
|
|
|
|
|
- document.getElementById('userSection').classList.remove('active');
|
|
|
|
|
- document.getElementById('authSection').style.display = 'block';
|
|
|
|
|
-
|
|
|
|
|
- document.getElementById('loginForm').reset();
|
|
|
|
|
- document.getElementById('registerForm').reset();
|
|
|
|
|
-
|
|
|
|
|
- // Reset edit profile form and hide it
|
|
|
|
|
- hideEditProfileForm();
|
|
|
|
|
-
|
|
|
|
|
- clearMessages();
|
|
|
|
|
-
|
|
|
|
|
- switchTab('login');
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function toggleEditProfileForm() {
|
|
|
|
|
- const formSection = document.getElementById('editProfileSection');
|
|
|
|
|
- const isVisible = formSection.style.display === 'block';
|
|
|
|
|
-
|
|
|
|
|
- if (isVisible) {
|
|
|
|
|
- hideEditProfileForm();
|
|
|
|
|
- } else {
|
|
|
|
|
- showEditProfileForm();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function showEditProfileForm() {
|
|
|
|
|
- const formSection = document.getElementById('editProfileSection');
|
|
|
|
|
- const actionBtn = document.getElementById('showEditProfileBtn');
|
|
|
|
|
-
|
|
|
|
|
- formSection.style.display = 'block';
|
|
|
|
|
- actionBtn.textContent = 'Hide Edit Profile';
|
|
|
|
|
-
|
|
|
|
|
- // Clear any previous messages
|
|
|
|
|
- clearEditProfileMessages();
|
|
|
|
|
-
|
|
|
|
|
- // Pre-populate email field with current user's email
|
|
|
|
|
- if (currentUser) {
|
|
|
|
|
- document.getElementById('editEmail').value = currentUser.email || '';
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Focus on email input first since that's the most common change
|
|
|
|
|
- setTimeout(() => document.getElementById('editEmail').focus(), 100);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function hideEditProfileForm() {
|
|
|
|
|
- const formSection = document.getElementById('editProfileSection');
|
|
|
|
|
- const actionBtn = document.getElementById('showEditProfileBtn');
|
|
|
|
|
-
|
|
|
|
|
- formSection.style.display = 'none';
|
|
|
|
|
- actionBtn.textContent = 'Edit Profile';
|
|
|
|
|
-
|
|
|
|
|
- // Clear form and messages
|
|
|
|
|
- document.getElementById('editProfileForm').reset();
|
|
|
|
|
- clearEditProfileMessages();
|
|
|
|
|
- }
|
|
|
|
|
- </script>
|
|
|
|
|
|
|
+ <script src="js/main.js"></script>
|
|
|
</body>
|
|
</body>
|
|
|
</html>
|
|
</html>
|