maps updates
This commit is contained in:
259
map/app/public/js/admin.js
Normal file
259
map/app/public/js/admin.js
Normal file
@@ -0,0 +1,259 @@
|
||||
// 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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user