Files
org-parking/frontend/pages/profile.html
Stefano Manfredi 7168fa4b72 Refactor to manager-centric model, add team calendar for all users
Key changes:
- Removed office-centric model (deleted offices.py, office-rules)
- Renamed to team-rules, managers are part of their own team
- Team calendar visible to all (read-only for employees)
- Admins can have a manager assigned
2025-12-02 13:30:04 +00:00

207 lines
8.9 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Profile - Parking Manager</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<aside class="sidebar">
<div class="sidebar-header">
<h1>Parking Manager</h1>
</div>
<nav class="sidebar-nav"></nav>
<div class="sidebar-footer">
<div class="user-menu">
<button class="user-button" id="userMenuButton">
<div class="user-avatar">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
</div>
<div class="user-info">
<div class="user-name" id="userName">Loading...</div>
<div class="user-role" id="userRole">-</div>
</div>
</button>
<div class="user-dropdown" id="userDropdown" style="display: none;">
<a href="/profile" class="dropdown-item">Profile</a>
<a href="/settings" class="dropdown-item">Settings</a>
<hr class="dropdown-divider">
<button class="dropdown-item" id="logoutButton">Logout</button>
</div>
</div>
</div>
</aside>
<main class="main-content">
<header class="page-header">
<h2>Profile</h2>
</header>
<div class="content-wrapper">
<div class="card">
<div class="card-header">
<h3>Personal Information</h3>
</div>
<div class="card-body">
<!-- LDAP Notice -->
<div id="ldapNotice" class="form-notice" style="display: none; margin-bottom: 1rem;">
<small>Your account is managed by LDAP. Some information cannot be changed here.</small>
</div>
<form id="profileForm">
<div class="form-group">
<label for="name">Full Name</label>
<input type="text" id="name" required>
<small id="nameHelp" class="text-muted" style="display: none;">Managed by LDAP</small>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" disabled>
<small class="text-muted">Email cannot be changed</small>
</div>
<div class="form-group">
<label for="role">Role</label>
<input type="text" id="role" disabled>
<small class="text-muted">Role is assigned by your administrator</small>
</div>
<div class="form-group">
<label for="manager">Manager</label>
<input type="text" id="manager" disabled>
<small class="text-muted">Your manager is assigned by the administrator</small>
</div>
<div class="form-actions" id="profileActions">
<button type="submit" class="btn btn-dark">Save Changes</button>
</div>
</form>
</div>
</div>
<!-- Password section - hidden for LDAP users -->
<div class="card" id="passwordCard">
<div class="card-header">
<h3>Change Password</h3>
</div>
<div class="card-body">
<form id="passwordForm">
<div class="form-group">
<label for="currentPassword">Current Password</label>
<input type="password" id="currentPassword" required>
</div>
<div class="form-group">
<label for="newPassword">New Password</label>
<input type="password" id="newPassword" required minlength="8">
<small>Minimum 8 characters</small>
</div>
<div class="form-group">
<label for="confirmPassword">Confirm New Password</label>
<input type="password" id="confirmPassword" required>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-dark">Change Password</button>
</div>
</form>
</div>
</div>
</div>
</main>
<script src="/js/api.js"></script>
<script src="/js/utils.js"></script>
<script src="/js/nav.js"></script>
<script>
let currentUser = null;
let isLdapUser = false;
document.addEventListener('DOMContentLoaded', async () => {
currentUser = await api.requireAuth();
if (!currentUser) return;
await loadProfile();
setupEventListeners();
});
async function loadProfile() {
const response = await api.get('/api/users/me/profile');
if (response && response.ok) {
const profile = await response.json();
isLdapUser = profile.is_ldap_user;
// Populate form
document.getElementById('name').value = profile.name || '';
document.getElementById('email').value = profile.email;
document.getElementById('role').value = profile.role;
document.getElementById('manager').value = profile.manager_name || 'None';
// LDAP mode adjustments
if (isLdapUser) {
document.getElementById('ldapNotice').style.display = 'block';
document.getElementById('name').disabled = true;
document.getElementById('nameHelp').style.display = 'block';
document.getElementById('profileActions').style.display = 'none';
document.getElementById('passwordCard').style.display = 'none';
}
}
}
function setupEventListeners() {
// Profile form
document.getElementById('profileForm').addEventListener('submit', async (e) => {
e.preventDefault();
if (isLdapUser) {
utils.showMessage('Profile is managed by LDAP', 'error');
return;
}
const data = {
name: document.getElementById('name').value
};
const response = await api.put('/api/users/me/profile', data);
if (response && response.ok) {
utils.showMessage('Profile updated successfully', 'success');
// Update nav display
const nameEl = document.getElementById('userName');
if (nameEl) nameEl.textContent = data.name;
} else {
const error = await response.json();
utils.showMessage(error.detail || 'Failed to update profile', 'error');
}
});
// Password form
document.getElementById('passwordForm').addEventListener('submit', async (e) => {
e.preventDefault();
const newPassword = document.getElementById('newPassword').value;
const confirmPassword = document.getElementById('confirmPassword').value;
if (newPassword !== confirmPassword) {
utils.showMessage('Passwords do not match', 'error');
return;
}
const data = {
current_password: document.getElementById('currentPassword').value,
new_password: newPassword
};
const response = await api.post('/api/users/me/change-password', data);
if (response && response.ok) {
utils.showMessage('Password changed successfully', 'success');
document.getElementById('passwordForm').reset();
} else {
const error = await response.json();
utils.showMessage(error.detail || 'Failed to change password', 'error');
}
});
}
</script>
</body>
</html>