Drone management improvements

This commit is contained in:
2026-06-21 17:26:42 -04:00
parent 5e33c1d47b
commit a3f1a10bf5
3 changed files with 453 additions and 88 deletions
+69 -4
View File
@@ -86,6 +86,21 @@
.dropdown-menu a:first-child { border-radius: 5px 5px 0 0; }
.dropdown-menu a:last-child { border-radius: 0 0 5px 5px; }
.shortcut { font-size: 0.8rem; color: #999; margin-left: 1rem; }
.notification-badge {
min-width: 1.4rem;
height: 1.4rem;
padding: 0 0.35rem;
border-radius: 999px;
background: #e74c3c;
color: white;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
font-weight: 700;
line-height: 1;
}
.notification-badge[hidden] { display: none; }
`;
document.head.appendChild(style);
}
@@ -97,8 +112,9 @@
return `<a href="#" data-topbar-action="${action}"${idAttr}${hidden}>${label} ${shortcutText}</a>`;
}
function navLink(label, href) {
return `<a href="${href}">${label}</a>`;
function navLink(label, href, id = '') {
const idAttr = id ? ` id="${id}"` : '';
return `<a href="${href}"${idAttr}>${label}</a>`;
}
function normalizeTopbar() {
@@ -138,12 +154,14 @@
</div>
</div>
<div class="dropdown">
<button class="btn btn-warning dropdown-toggle" id="adminDropdownBtn">⚙️ Menu</button>
<button class="btn btn-warning dropdown-toggle" id="adminDropdownBtn">
⚙️ Menu <span class="notification-badge" id="drone-request-menu-badge" hidden>0</span>
</button>
<div class="dropdown-menu" id="adminDropdownMenu">
${navLink('🏠 Admin View', '/admin')}
${navLink('🎛️ ATC View', '/atc')}
${navLink('📊 Reports', '/reports')}
${navLink('🛸 Drone Requests', '/drone-requests')}
${navLink('🛸 Drone Requests <span class="notification-badge" id="drone-request-badge" hidden>0</span>', '/drone-requests')}
${navLink('📔 Journal Log', '/journal')}
${actionLink('✈️ User Aircraft', 'user-aircraft', '', 'user-aircraft-dropdown')}
${actionLink('👥 User Management', 'user-management', '', 'user-management-dropdown')}
@@ -220,6 +238,51 @@
}
}
async function refreshDroneRequestBadge() {
const badges = [
document.getElementById('drone-request-badge'),
document.getElementById('drone-request-menu-badge'),
].filter(Boolean);
if (!badges.length) return;
const token = localStorage.getItem('ppr_access_token');
if (!token) {
badges.forEach(badge => {
badge.hidden = true;
});
return;
}
try {
const response = await fetch('/api/v1/drone-requests/?status=NEW&limit=100', {
headers: { 'Authorization': `Bearer ${token}` }
});
if (!response.ok) {
badges.forEach(badge => {
badge.hidden = true;
});
return;
}
const requests = await response.json();
const count = Array.isArray(requests) ? requests.length : 0;
const title = count === 1
? '1 drone request waiting for approval'
: `${count} drone requests waiting for approval`;
badges.forEach(badge => {
badge.textContent = count > 99 ? '99+' : String(count);
badge.hidden = count === 0;
badge.title = title;
});
} catch (error) {
badges.forEach(badge => {
badge.hidden = true;
});
}
}
window.refreshDroneRequestBadge = refreshDroneRequestBadge;
document.addEventListener('click', event => {
const toggle = event.target.closest('.dropdown-toggle');
const action = event.target.closest('[data-topbar-action]');
@@ -265,6 +328,8 @@
document.addEventListener('DOMContentLoaded', () => {
normalizeTopbar();
updateRoleVisibility();
refreshDroneRequestBadge();
handleDeferredAction();
window.setInterval(refreshDroneRequestBadge, 60000);
});
})();