Files
org-parking/frontend/pages/presence.html
Stefano Manfredi c74a0ed350 Initial commit: Parking Manager
Features:
- Manager-centric parking spot management
- Fair assignment algorithm (parking/presence ratio)
- Presence tracking calendar
- Closing days (specific & weekly recurring)
- Guarantees and exclusions
- Authelia/LLDAP integration for SSO

Stack:
- FastAPI backend
- SQLite database
- Vanilla JS frontend
- Docker deployment
2025-11-26 23:37:50 +00:00

187 lines
8.3 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Presence - 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>My Presence</h2>
<div class="header-actions">
<button class="btn btn-secondary" id="bulkMarkBtn">Bulk Mark</button>
</div>
</header>
<div class="content-wrapper">
<div class="card presence-card">
<div class="calendar-header">
<button class="btn-icon" id="prevMonth">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="15 18 9 12 15 6"></polyline>
</svg>
</button>
<h3 id="currentMonth">Loading...</h3>
<button class="btn-icon" id="nextMonth">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="9 18 15 12 9 6"></polyline>
</svg>
</button>
</div>
<div class="calendar-grid" id="calendarGrid"></div>
<div class="legend">
<div class="legend-item">
<div class="legend-color status-present"></div>
<span>Present (Office)</span>
</div>
<div class="legend-item">
<div class="legend-color status-remote"></div>
<span>Remote</span>
</div>
<div class="legend-item">
<div class="legend-color status-absent"></div>
<span>Absent</span>
</div>
</div>
</div>
</div>
</main>
<!-- Day Modal -->
<div class="modal" id="dayModal" style="display: none;">
<div class="modal-content modal-small">
<div class="modal-header">
<h3 id="dayModalTitle">Mark Presence</h3>
<button class="modal-close" id="closeDayModal">&times;</button>
</div>
<div class="modal-body">
<div class="status-buttons">
<button class="status-btn" data-status="present">
<div class="status-icon status-present"></div>
<span>Present</span>
</button>
<button class="status-btn" data-status="remote">
<div class="status-icon status-remote"></div>
<span>Remote</span>
</button>
<button class="status-btn" data-status="absent">
<div class="status-icon status-absent"></div>
<span>Absent</span>
</button>
</div>
<div id="parkingSection" style="display: none; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--border);">
<div id="parkingInfo" style="margin-bottom: 0.75rem; font-size: 0.9rem;"></div>
<div style="display: flex; gap: 0.5rem;">
<button class="btn btn-secondary" style="flex: 1;" id="reassignParkingBtn">Reassign</button>
<button class="btn btn-secondary" style="flex: 1;" id="releaseParkingBtn">Release</button>
</div>
</div>
<button class="btn btn-secondary btn-full" id="clearDayBtn" style="margin-top: 1rem;">Clear Presence</button>
</div>
</div>
</div>
<!-- Reassign Parking Modal -->
<div class="modal" id="reassignModal" style="display: none;">
<div class="modal-content modal-small">
<div class="modal-header">
<h3>Reassign Parking Spot</h3>
<button class="modal-close" id="closeReassignModal">&times;</button>
</div>
<div class="modal-body">
<p id="reassignSpotInfo" style="margin-bottom: 1rem; font-size: 0.9rem;"></p>
<div class="form-group">
<label for="reassignUser">Assign to</label>
<select id="reassignUser" required>
<option value="">Select user...</option>
</select>
</div>
<div class="form-actions">
<button type="button" class="btn btn-secondary" id="cancelReassign">Cancel</button>
<button type="button" class="btn btn-dark" id="confirmReassign">Reassign</button>
</div>
</div>
</div>
</div>
<!-- Bulk Mark Modal -->
<div class="modal" id="bulkMarkModal" style="display: none;">
<div class="modal-content">
<div class="modal-header">
<h3>Bulk Mark Presence</h3>
<button class="modal-close" id="closeBulkModal">&times;</button>
</div>
<div class="modal-body">
<form id="bulkMarkForm">
<div class="form-group">
<label for="startDate">Start Date</label>
<input type="date" id="startDate" required>
</div>
<div class="form-group">
<label for="endDate">End Date</label>
<input type="date" id="endDate" required>
</div>
<div class="form-group">
<label for="bulkStatus">Status</label>
<select id="bulkStatus" required>
<option value="present">Present (Office)</option>
<option value="remote">Remote</option>
<option value="absent">Absent</option>
</select>
</div>
<div class="form-group checkbox-group">
<label class="checkbox-label">
<input type="checkbox" id="weekdaysOnly">
<span>Weekdays only (Mon-Fri)</span>
</label>
</div>
<div class="form-actions">
<button type="button" class="btn btn-secondary" id="cancelBulk">Cancel</button>
<button type="submit" class="btn btn-dark">Mark Dates</button>
</div>
</form>
</div>
</div>
</div>
<script src="/js/api.js"></script>
<script src="/js/utils.js"></script>
<script src="/js/nav.js"></script>
<script src="/js/presence.js"></script>
</body>
</html>