Spaces:
Configuration error
Configuration error
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Admin Panel - AI Resume Builder</title> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet"> | |
| <style> | |
| .navbar-brand { | |
| font-weight: bold; | |
| } | |
| .table-actions { | |
| white-space: nowrap; | |
| } | |
| .user-count { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 20px; | |
| border-radius: 10px; | |
| margin-bottom: 30px; | |
| } | |
| .delete-btn { | |
| transition: all 0.3s ease; | |
| } | |
| .delete-btn:hover { | |
| transform: scale(1.1); | |
| } | |
| .admin-badge { | |
| background-color: #dc3545; | |
| color: white; | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| font-size: 0.75rem; | |
| } | |
| .user-badge { | |
| background-color: #6c757d; | |
| color: white; | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| font-size: 0.75rem; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Navigation --> | |
| <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> | |
| <div class="container"> | |
| <a class="navbar-brand" href="{{ url_for('admin_panel') }}"> | |
| <i class="bi bi-shield-lock"></i> Admin Panel | |
| </a> | |
| <div class="navbar-nav ms-auto"> | |
| <a class="nav-link" href="{{ url_for('profile') }}"> | |
| <i class="bi bi-person-circle"></i> Back to Profile | |
| </a> | |
| <a class="nav-link" href="{{ url_for('logout') }}"> | |
| <i class="bi bi-box-arrow-right"></i> Logout | |
| </a> | |
| </div> | |
| </div> | |
| </nav> | |
| <!-- Main Content --> | |
| <div class="container mt-4"> | |
| <!-- User Statistics --> | |
| <div class="user-count text-center"> | |
| <h2><i class="bi bi-people-fill"></i> User Management</h2> | |
| <p class="mb-0 h4">Total Users: {{ users|length }}</p> | |
| </div> | |
| <!-- Users Table --> | |
| <div class="card"> | |
| <div class="card-header bg-primary text-white"> | |
| <h5 class="mb-0"><i class="bi bi-table"></i> Registered Users</h5> | |
| </div> | |
| <div class="card-body"> | |
| <div class="table-responsive"> | |
| <table class="table table-hover" id="usersTable"> | |
| <thead> | |
| <tr> | |
| <th>ID</th> | |
| <th>Name</th> | |
| <th>Email</th> | |
| <th>Role</th> | |
| <th>Created At</th> | |
| <th>Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| {% for user in users %} | |
| <tr data-user-id="{{ user.id }}"> | |
| <td><code>{{ user.id|string|truncate(8, True, '') }}...</code></td> | |
| <td>{{ user.name }}</td> | |
| <td>{{ user.email }}</td> | |
| <td> | |
| {% if user.is_admin %} | |
| <span class="admin-badge">Admin</span> | |
| {% else %} | |
| <span class="user-badge">User</span> | |
| {% endif %} | |
| </td> | |
| <td>{{ user.created_at.strftime('%Y-%m-%d %H:%M') if user.created_at else 'N/A' }}</td> | |
| <td class="table-actions"> | |
| {% if not user.is_admin %} | |
| <button class="btn btn-sm btn-danger delete-btn" | |
| onclick="deleteUser('{{ user.id }}', '{{ user.email }}')" | |
| title="Delete User"> | |
| <i class="bi bi-trash"></i> | |
| </button> | |
| {% endif %} | |
| </td> | |
| </tr> | |
| {% endfor %} | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Delete Confirmation Modal --> | |
| <div class="modal fade" id="deleteModal" tabindex="-1"> | |
| <div class="modal-dialog"> | |
| <div class="modal-content"> | |
| <div class="modal-header bg-danger text-white"> | |
| <h5 class="modal-title"> | |
| <i class="bi bi-exclamation-triangle"></i> Confirm Delete | |
| </h5> | |
| <button type="button" class="btn-close" data-bs-dismiss="modal"></button> | |
| </div> | |
| <div class="modal-body"> | |
| <p>Are you sure you want to delete this user?</p> | |
| <div class="alert alert-warning"> | |
| <i class="bi bi-warning"></i> | |
| <strong>Warning:</strong> This will permanently delete the user and all their profile data including: | |
| <ul class="mb-0 mt-2"> | |
| <li>Introduction information</li> | |
| <li>Profile summary</li> | |
| <li>Work experience</li> | |
| <li>Projects</li> | |
| <li>Education</li> | |
| <li>Skills</li> | |
| <li>Achievements</li> | |
| </ul> | |
| </div> | |
| <p><strong>User to delete:</strong> <span id="deleteUserEmail"></span></p> | |
| </div> | |
| <div class="modal-footer"> | |
| <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button> | |
| <button type="button" class="btn btn-danger" id="confirmDelete"> | |
| <i class="bi bi-trash"></i> Delete User | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Success Toast --> | |
| <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11"> | |
| <div id="successToast" class="toast" role="alert"> | |
| <div class="toast-header bg-success text-white"> | |
| <i class="bi bi-check-circle me-2"></i> | |
| <strong class="me-auto">Success</strong> | |
| <button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast"></button> | |
| </div> | |
| <div class="toast-body" id="successMessage"> | |
| User deleted successfully! | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Error Toast --> | |
| <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11"> | |
| <div id="errorToast" class="toast" role="alert"> | |
| <div class="toast-header bg-danger text-white"> | |
| <i class="bi bi-exclamation-circle me-2"></i> | |
| <strong class="me-auto">Error</strong> | |
| <button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast"></button> | |
| </div> | |
| <div class="toast-body" id="errorMessage"> | |
| An error occurred! | |
| </div> | |
| </div> | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> | |
| <script> | |
| let userToDelete = null; | |
| const deleteModal = new bootstrap.Modal(document.getElementById('deleteModal')); | |
| const successToast = new bootstrap.Toast(document.getElementById('successToast')); | |
| const errorToast = new bootstrap.Toast(document.getElementById('errorToast')); | |
| function deleteUser(userId, userEmail) { | |
| userToDelete = userId; | |
| document.getElementById('deleteUserEmail').textContent = userEmail; | |
| deleteModal.show(); | |
| } | |
| document.getElementById('confirmDelete').addEventListener('click', async function() { | |
| if (!userToDelete) return; | |
| try { | |
| const response = await fetch(`/api/admin/users/${userToDelete}`, { | |
| method: 'DELETE', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| } | |
| }); | |
| const data = await response.json(); | |
| if (data.success) { | |
| // Remove row from table | |
| const row = document.querySelector(`tr[data-user-id="${userToDelete}"]`); | |
| if (row) { | |
| row.remove(); | |
| } | |
| // Update user count | |
| const userCount = document.querySelectorAll('#usersTable tbody tr').length; | |
| document.querySelector('.user-count p').textContent = `Total Users: ${userCount}`; | |
| // Show success message | |
| document.getElementById('successMessage').textContent = data.message; | |
| successToast.show(); | |
| } else { | |
| // Show error message | |
| document.getElementById('errorMessage').textContent = data.error || 'Failed to delete user'; | |
| errorToast.show(); | |
| } | |
| } catch (error) { | |
| console.error('Error:', error); | |
| document.getElementById('errorMessage').textContent = 'Network error occurred'; | |
| errorToast.show(); | |
| } finally { | |
| deleteModal.hide(); | |
| userToDelete = null; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |