// Location management (CRUD operations) import { map } from './map-manager.js'; import { showStatus, updateLocationCount, escapeHtml } from './utils.js'; import { currentUser } from './auth.js'; export let markers = []; export let currentEditingLocation = null; export async function loadLocations() { try { const response = await fetch('/api/locations'); const data = await response.json(); if (data.success) { displayLocations(data.locations); updateLocationCount(data.locations.length); } else { throw new Error(data.error || 'Failed to load locations'); } } catch (error) { console.error('Error loading locations:', error); showStatus('Failed to load locations', 'error'); } } export function displayLocations(locations) { // Clear existing markers markers.forEach(marker => { if (marker && map) { map.removeLayer(marker); } }); markers = []; // Add new markers locations.forEach(location => { if (location.latitude && location.longitude) { const marker = createLocationMarker(location); if (marker) { markers.push(marker); } } }); console.log(`Displayed ${markers.length} locations`); } function createLocationMarker(location) { if (!map) { console.warn('Map not initialized, skipping marker creation'); return null; } const lat = parseFloat(location.latitude); const lng = parseFloat(location.longitude); // Determine marker color based on support level let markerColor = 'blue'; if (location['Support Level']) { const level = parseInt(location['Support Level']); switch(level) { case 1: markerColor = 'green'; break; case 2: markerColor = 'yellow'; break; case 3: markerColor = 'orange'; break; case 4: markerColor = 'red'; break; } } const marker = L.circleMarker([lat, lng], { radius: 8, fillColor: markerColor, color: '#fff', weight: 2, opacity: 1, fillOpacity: 0.8 }).addTo(map); const popupContent = createPopupContent(location); marker.bindPopup(popupContent); marker._locationData = location; return marker; } function createPopupContent(location) { const locationId = location.Id || location.id || location.ID || location._id; const name = [location['First Name'], location['Last Name']] .filter(Boolean).join(' ') || 'Unknown'; const address = location.Address || 'No address'; const supportLevel = location['Support Level'] ? `Level ${location['Support Level']}` : 'Not specified'; return ` `; } export async function handleAddLocation(e) { e.preventDefault(); const formData = new FormData(e.target); const data = {}; // Convert form data to object for (let [key, value] of formData.entries()) { // Map form field names to NocoDB column names if (key === 'latitude') data.latitude = value.trim(); else if (key === 'longitude') data.longitude = value.trim(); else if (key === 'Geo-Location') data['Geo-Location'] = value.trim(); else if (value.trim() !== '') { data[key] = value.trim(); } } // Ensure geo-location is set if (data.latitude && data.longitude) { data['Geo-Location'] = `${data.latitude};${data.longitude}`; } // Handle checkbox data.Sign = document.getElementById('sign').checked; try { const response = await fetch('/api/locations', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); const result = await response.json(); if (result.success) { showStatus('Location added successfully!', 'success'); closeAddModal(); loadLocations(); } else { throw new Error(result.error || 'Failed to add location'); } } catch (error) { console.error('Error adding location:', error); showStatus(error.message || 'Failed to add location', 'error'); } } export function openEditForm(location) { currentEditingLocation = location; // Extract ID - check multiple possible field names const locationId = location.Id || location.id || location.ID || location._id; if (!locationId) { console.error('No ID found in location object. Available fields:', Object.keys(location)); showStatus('Error: Location ID not found. Check console for details.', 'error'); return; } // Store the ID in a data attribute for later use document.getElementById('edit-location-id').value = locationId; document.getElementById('edit-location-id').setAttribute('data-location-id', locationId); // Populate form fields document.getElementById('edit-first-name').value = location['First Name'] || ''; document.getElementById('edit-last-name').value = location['Last Name'] || ''; document.getElementById('edit-location-email').value = location.Email || ''; document.getElementById('edit-location-phone').value = location.Phone || ''; document.getElementById('edit-location-unit').value = location['Unit Number'] || ''; document.getElementById('edit-support-level').value = location['Support Level'] || ''; document.getElementById('edit-location-address').value = location.Address || ''; document.getElementById('edit-sign').checked = location.Sign === true || location.Sign === 'true' || location.Sign === 1; document.getElementById('edit-sign-size').value = location['Sign Size'] || ''; document.getElementById('edit-location-notes').value = location.Notes || ''; document.getElementById('edit-location-lat').value = location.latitude || ''; document.getElementById('edit-location-lng').value = location.longitude || ''; document.getElementById('edit-geo-location').value = location['Geo-Location'] || ''; // Show edit footer document.getElementById('edit-footer').classList.remove('hidden'); } export function closeEditForm() { document.getElementById('edit-footer').classList.add('hidden'); currentEditingLocation = null; } export async function handleEditLocation(e) { e.preventDefault(); if (!currentEditingLocation) return; // Get the stored location ID const locationIdElement = document.getElementById('edit-location-id'); const locationId = locationIdElement.getAttribute('data-location-id') || locationIdElement.value; if (!locationId || locationId === 'undefined') { showStatus('Error: Location ID not found', 'error'); return; } const formData = new FormData(e.target); const data = {}; // Convert form data to object for (let [key, value] of formData.entries()) { // Skip the ID field if (key === 'id' || key === 'Id' || key === 'ID') continue; if (value !== null && value !== undefined) { data[key] = value.trim(); } } // Ensure geo-location is set if (data.latitude && data.longitude) { data['Geo-Location'] = `${data.latitude};${data.longitude}`; } // Handle checkbox data.Sign = document.getElementById('edit-sign').checked; try { const response = await fetch(`/api/locations/${locationId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); const responseText = await response.text(); let result; try { result = JSON.parse(responseText); } catch (e) { console.error('Failed to parse response:', responseText); throw new Error(`Server response error: ${response.status} ${response.statusText}`); } if (result.success) { showStatus('Location updated successfully!', 'success'); closeEditForm(); loadLocations(); } else { throw new Error(result.error || 'Failed to update location'); } } catch (error) { console.error('Error updating location:', error); showStatus(`Update failed: ${error.message}`, 'error'); } } export async function handleDeleteLocation() { if (!currentEditingLocation) return; // Get the stored location ID const locationIdElement = document.getElementById('edit-location-id'); const locationId = locationIdElement.getAttribute('data-location-id') || locationIdElement.value; if (!locationId || locationId === 'undefined') { showStatus('Error: Location ID not found', 'error'); return; } if (!confirm('Are you sure you want to delete this location?')) { return; } try { const response = await fetch(`/api/locations/${locationId}`, { method: 'DELETE' }); const result = await response.json(); if (result.success) { showStatus('Location deleted successfully!', 'success'); closeEditForm(); loadLocations(); } else { throw new Error(result.error || 'Failed to delete location'); } } catch (error) { console.error('Error deleting location:', error); showStatus(error.message || 'Failed to delete location', 'error'); } } export function closeAddModal() { const modal = document.getElementById('add-modal'); modal.classList.add('hidden'); document.getElementById('location-form').reset(); } export function openAddModal(lat, lng) { const modal = document.getElementById('add-modal'); const latInput = document.getElementById('location-lat'); const lngInput = document.getElementById('location-lng'); const geoInput = document.getElementById('geo-location'); // Set coordinates latInput.value = lat.toFixed(8); lngInput.value = lng.toFixed(8); geoInput.value = `${lat.toFixed(8)};${lng.toFixed(8)}`; // Clear other fields document.getElementById('location-form').reset(); latInput.value = lat.toFixed(8); lngInput.value = lng.toFixed(8); geoInput.value = `${lat.toFixed(8)};${lng.toFixed(8)}`; // Show modal modal.classList.remove('hidden'); // Trigger custom event for auto address lookup const autoLookupEvent = new CustomEvent('autoAddressLookup', { detail: { mode: 'add', lat, lng } }); document.dispatchEvent(autoLookupEvent); }