260 lines
8.1 KiB
JavaScript
260 lines
8.1 KiB
JavaScript
// Admin panel JavaScript
|
|
let adminMap = null;
|
|
let startMarker = null;
|
|
|
|
// Initialize when DOM is loaded
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
checkAdminAuth();
|
|
initializeAdminMap();
|
|
loadCurrentStartLocation();
|
|
setupEventListeners();
|
|
});
|
|
|
|
// Check if user is authenticated as admin
|
|
async function checkAdminAuth() {
|
|
try {
|
|
const response = await fetch('/api/auth/check');
|
|
const data = await response.json();
|
|
|
|
if (!data.authenticated || !data.user?.isAdmin) {
|
|
window.location.href = '/login.html';
|
|
return;
|
|
}
|
|
|
|
// Display admin info
|
|
document.getElementById('admin-info').innerHTML = `
|
|
<span>👤 ${escapeHtml(data.user.email)}</span>
|
|
<button id="logout-btn" class="btn btn-secondary btn-sm">Logout</button>
|
|
`;
|
|
|
|
document.getElementById('logout-btn').addEventListener('click', handleLogout);
|
|
|
|
} catch (error) {
|
|
console.error('Auth check failed:', error);
|
|
window.location.href = '/login.html';
|
|
}
|
|
}
|
|
|
|
// Initialize the admin map
|
|
function initializeAdminMap() {
|
|
adminMap = L.map('admin-map').setView([53.5461, -113.4938], 11);
|
|
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
|
maxZoom: 19,
|
|
minZoom: 2
|
|
}).addTo(adminMap);
|
|
|
|
// Add click handler to set location
|
|
adminMap.on('click', handleMapClick);
|
|
|
|
// Update coordinates when map moves
|
|
adminMap.on('moveend', updateCoordinatesFromMap);
|
|
}
|
|
|
|
// Load current start location
|
|
async function loadCurrentStartLocation() {
|
|
try {
|
|
const response = await fetch('/api/admin/start-location');
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
const { latitude, longitude, zoom } = data.location;
|
|
|
|
// Update form fields
|
|
document.getElementById('start-lat').value = latitude;
|
|
document.getElementById('start-lng').value = longitude;
|
|
document.getElementById('start-zoom').value = zoom;
|
|
|
|
// Update map
|
|
adminMap.setView([latitude, longitude], zoom);
|
|
updateStartMarker(latitude, longitude);
|
|
|
|
// Show source info
|
|
if (data.source) {
|
|
const sourceText = data.source === 'database' ? 'Loaded from database' :
|
|
data.source === 'environment' ? 'Using environment defaults' :
|
|
'Using system defaults';
|
|
showStatus(sourceText, 'info');
|
|
}
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Failed to load start location:', error);
|
|
showStatus('Failed to load current start location', 'error');
|
|
}
|
|
}
|
|
|
|
// Handle map click
|
|
function handleMapClick(e) {
|
|
const { lat, lng } = e.latlng;
|
|
|
|
document.getElementById('start-lat').value = lat.toFixed(6);
|
|
document.getElementById('start-lng').value = lng.toFixed(6);
|
|
|
|
updateStartMarker(lat, lng);
|
|
}
|
|
|
|
// Update marker position
|
|
function updateStartMarker(lat, lng) {
|
|
if (startMarker) {
|
|
startMarker.setLatLng([lat, lng]);
|
|
} else {
|
|
startMarker = L.marker([lat, lng], {
|
|
draggable: true,
|
|
title: 'Start Location'
|
|
}).addTo(adminMap);
|
|
|
|
// Update coordinates when marker is dragged
|
|
startMarker.on('dragend', (e) => {
|
|
const position = e.target.getLatLng();
|
|
document.getElementById('start-lat').value = position.lat.toFixed(6);
|
|
document.getElementById('start-lng').value = position.lng.toFixed(6);
|
|
});
|
|
}
|
|
}
|
|
|
|
// Update coordinates from current map view
|
|
function updateCoordinatesFromMap() {
|
|
const center = adminMap.getCenter();
|
|
const zoom = adminMap.getZoom();
|
|
|
|
document.getElementById('start-zoom').value = zoom;
|
|
}
|
|
|
|
// Setup event listeners
|
|
function setupEventListeners() {
|
|
// Use current view button
|
|
document.getElementById('use-current-view').addEventListener('click', () => {
|
|
const center = adminMap.getCenter();
|
|
const zoom = adminMap.getZoom();
|
|
|
|
document.getElementById('start-lat').value = center.lat.toFixed(6);
|
|
document.getElementById('start-lng').value = center.lng.toFixed(6);
|
|
document.getElementById('start-zoom').value = zoom;
|
|
|
|
updateStartMarker(center.lat, center.lng);
|
|
showStatus('Captured current map view', 'success');
|
|
});
|
|
|
|
// Save button
|
|
document.getElementById('save-start-location').addEventListener('click', saveStartLocation);
|
|
|
|
// Coordinate input changes
|
|
document.getElementById('start-lat').addEventListener('change', updateMapFromInputs);
|
|
document.getElementById('start-lng').addEventListener('change', updateMapFromInputs);
|
|
document.getElementById('start-zoom').addEventListener('change', updateMapFromInputs);
|
|
}
|
|
|
|
// Update map from input fields
|
|
function updateMapFromInputs() {
|
|
const lat = parseFloat(document.getElementById('start-lat').value);
|
|
const lng = parseFloat(document.getElementById('start-lng').value);
|
|
const zoom = parseInt(document.getElementById('start-zoom').value);
|
|
|
|
if (!isNaN(lat) && !isNaN(lng) && !isNaN(zoom)) {
|
|
adminMap.setView([lat, lng], zoom);
|
|
updateStartMarker(lat, lng);
|
|
}
|
|
}
|
|
|
|
// Save start location
|
|
async function saveStartLocation() {
|
|
const lat = parseFloat(document.getElementById('start-lat').value);
|
|
const lng = parseFloat(document.getElementById('start-lng').value);
|
|
const zoom = parseInt(document.getElementById('start-zoom').value);
|
|
|
|
// Validate
|
|
if (isNaN(lat) || isNaN(lng) || isNaN(zoom)) {
|
|
showStatus('Please enter valid coordinates and zoom level', 'error');
|
|
return;
|
|
}
|
|
|
|
if (lat < -90 || lat > 90 || lng < -180 || lng > 180) {
|
|
showStatus('Coordinates out of valid range', 'error');
|
|
return;
|
|
}
|
|
|
|
if (zoom < 2 || zoom > 19) {
|
|
showStatus('Zoom level must be between 2 and 19', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/api/admin/start-location', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
latitude: lat,
|
|
longitude: lng,
|
|
zoom: zoom
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
showStatus('Start location saved successfully!', 'success');
|
|
} else {
|
|
throw new Error(data.error || 'Failed to save');
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Save error:', error);
|
|
showStatus(error.message || 'Failed to save start location', 'error');
|
|
}
|
|
}
|
|
|
|
// Handle logout
|
|
async function handleLogout() {
|
|
if (!confirm('Are you sure you want to logout?')) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/api/auth/logout', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
window.location.href = '/login.html';
|
|
} else {
|
|
showStatus('Logout failed. Please try again.', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Logout error:', error);
|
|
showStatus('Logout failed. Please try again.', 'error');
|
|
}
|
|
}
|
|
|
|
// Show status message
|
|
function showStatus(message, type = 'info') {
|
|
const container = document.getElementById('status-container');
|
|
|
|
const messageDiv = document.createElement('div');
|
|
messageDiv.className = `status-message ${type}`;
|
|
messageDiv.textContent = message;
|
|
|
|
container.appendChild(messageDiv);
|
|
|
|
// Auto-remove after 5 seconds
|
|
setTimeout(() => {
|
|
messageDiv.remove();
|
|
}, 5000);
|
|
}
|
|
|
|
// Escape HTML
|
|
function escapeHtml(text) {
|
|
if (text === null || text === undefined) {
|
|
return '';
|
|
}
|
|
const div = document.createElement('div');
|
|
div.textContent = String(text);
|
|
return div.innerHTML;
|
|
}
|