597 lines
26 KiB
JavaScript
597 lines
26 KiB
JavaScript
import { map } from './map-manager.js';
|
||
import { showStatus } from './utils.js';
|
||
import { openAddModal } from './location-manager.js';
|
||
|
||
let edmontonParcelsLayer = null;
|
||
let isLoading = false;
|
||
let isLayerVisible = false;
|
||
let lastBounds = null;
|
||
let lastZoom = null;
|
||
|
||
/**
|
||
* Toggles the visibility of the Edmonton Parcel Addresses layer.
|
||
* Uses smart loading based on map bounds and zoom level.
|
||
*/
|
||
export async function toggleEdmontonParcelsLayer() {
|
||
const toggleBtn = document.getElementById('toggle-edmonton-layer-btn');
|
||
const mobileToggleBtn = document.getElementById('mobile-toggle-edmonton-layer-btn');
|
||
|
||
if (isLoading) {
|
||
console.log('Edmonton layer is already loading...');
|
||
return;
|
||
}
|
||
|
||
if (isLayerVisible) {
|
||
// Hide the layer
|
||
if (edmontonParcelsLayer && map.hasLayer(edmontonParcelsLayer)) {
|
||
map.removeLayer(edmontonParcelsLayer);
|
||
}
|
||
isLayerVisible = false;
|
||
toggleBtn?.classList.remove('active');
|
||
mobileToggleBtn?.classList.remove('active');
|
||
console.log('Edmonton addresses layer hidden');
|
||
|
||
// Remove map event listeners
|
||
map.off('moveend', onMapMoveEnd);
|
||
map.off('zoomend', onMapZoomEnd);
|
||
} else {
|
||
// Show the layer
|
||
isLayerVisible = true;
|
||
toggleBtn?.classList.add('active');
|
||
mobileToggleBtn?.classList.add('active');
|
||
console.log('Edmonton addresses layer enabled');
|
||
|
||
// Add map event listeners for dynamic loading
|
||
map.on('moveend', onMapMoveEnd);
|
||
map.on('zoomend', onMapZoomEnd);
|
||
|
||
// Load data for current view
|
||
await loadEdmontonData();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Loads Edmonton data for the current map bounds and zoom level
|
||
*/
|
||
async function loadEdmontonData(force = false) {
|
||
if (!isLayerVisible || isLoading) return;
|
||
|
||
const currentBounds = map.getBounds();
|
||
const currentZoom = map.getZoom();
|
||
|
||
// Check if we need to reload data
|
||
if (!force && lastBounds && lastZoom === currentZoom &&
|
||
lastBounds.contains(currentBounds)) {
|
||
return; // Current view is already covered
|
||
}
|
||
|
||
// Only load data if zoomed in enough (reduces server load)
|
||
if (currentZoom < 11) {
|
||
if (edmontonParcelsLayer && map.hasLayer(edmontonParcelsLayer)) {
|
||
map.removeLayer(edmontonParcelsLayer);
|
||
}
|
||
console.log('Zoom level too low for Edmonton data, zoom in to see addresses');
|
||
return;
|
||
}
|
||
|
||
isLoading = true;
|
||
const toggleBtn = document.getElementById('toggle-edmonton-layer-btn');
|
||
const mobileToggleBtn = document.getElementById('mobile-toggle-edmonton-layer-btn');
|
||
|
||
if (toggleBtn) toggleBtn.disabled = true;
|
||
if (mobileToggleBtn) mobileToggleBtn.disabled = true;
|
||
|
||
try {
|
||
// Expand bounds slightly to avoid edge loading issues
|
||
const expandedBounds = currentBounds.pad(0.1);
|
||
const boundsString = [
|
||
expandedBounds.getSouth(),
|
||
expandedBounds.getWest(),
|
||
expandedBounds.getNorth(),
|
||
expandedBounds.getEast()
|
||
].join(',');
|
||
|
||
const params = new URLSearchParams({
|
||
bounds: boundsString,
|
||
zoom: currentZoom.toString(),
|
||
limit: currentZoom > 15 ? '2000' : currentZoom > 12 ? '1000' : '500'
|
||
});
|
||
|
||
console.log(`Loading Edmonton addresses for zoom level ${currentZoom}, bounds: ${boundsString}`);
|
||
|
||
const response = await fetch(`/api/external/edmonton-parcels?${params}`);
|
||
if (!response.ok) {
|
||
throw new Error('Failed to fetch layer data from server.');
|
||
}
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
// Remove existing layer
|
||
if (edmontonParcelsLayer && map.hasLayer(edmontonParcelsLayer)) {
|
||
map.removeLayer(edmontonParcelsLayer);
|
||
}
|
||
|
||
// Create new layer with clustering optimized for the zoom level
|
||
const clusterRadius = currentZoom > 15 ? 30 : currentZoom > 12 ? 50 : 80;
|
||
edmontonParcelsLayer = L.markerClusterGroup({
|
||
chunkedLoading: true,
|
||
maxClusterRadius: clusterRadius,
|
||
disableClusteringAtZoom: 18,
|
||
showCoverageOnHover: false,
|
||
zoomToBoundsOnClick: true,
|
||
spiderfyOnMaxZoom: true,
|
||
removeOutsideVisibleBounds: true
|
||
});
|
||
|
||
const geoJsonLayer = L.geoJSON(result.data, {
|
||
pointToLayer: (feature, latlng) => {
|
||
const isMultiUnit = feature.properties.isMultiUnit;
|
||
|
||
if (isMultiUnit) {
|
||
// Use a custom HTML marker for multi-unit buildings (square)
|
||
const size = Math.max(12, Math.min(24, (currentZoom - 10) * 2));
|
||
const icon = L.divIcon({
|
||
className: 'multi-unit-marker',
|
||
html: `<div class="apartment-marker" style="
|
||
width: ${size}px;
|
||
height: ${size}px;
|
||
background-color: #ff6b35;
|
||
border: 2px solid #ffffff;
|
||
border-radius: 0;
|
||
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
|
||
"></div>`,
|
||
iconSize: [size, size],
|
||
iconAnchor: [size/2, size/2],
|
||
popupAnchor: [0, -size/2]
|
||
});
|
||
return L.marker(latlng, { icon: icon });
|
||
} else {
|
||
// Use circle marker for single units (round, red)
|
||
return L.circleMarker(latlng, {
|
||
radius: Math.max(3, Math.min(6, currentZoom - 10)),
|
||
fillColor: "#ba001e",
|
||
color: "#ffffff",
|
||
weight: 1,
|
||
opacity: 0.9,
|
||
fillOpacity: 0.7
|
||
});
|
||
}
|
||
},
|
||
onEachFeature: (feature, layer) => {
|
||
const props = feature.properties;
|
||
|
||
if (props.isMultiUnit) {
|
||
// Create apartment-style popup for multi-unit buildings
|
||
const popup = L.popup({
|
||
maxWidth: 320,
|
||
minWidth: 280,
|
||
closeButton: true,
|
||
className: 'apartment-popup'
|
||
}).setContent(createApartmentPopup(props));
|
||
|
||
layer.bindPopup(popup);
|
||
|
||
// Add event listener for when popup opens
|
||
layer.on('popupopen', function(e) {
|
||
setupApartmentPopupListeners(props);
|
||
});
|
||
} else {
|
||
// Simple popup for single units
|
||
const suite = props.suites && props.suites[0] ? props.suites[0] : {};
|
||
|
||
// Better suite/unit display logic
|
||
let suiteDisplay = '';
|
||
if (suite.suite && suite.suite.trim()) {
|
||
const unitLabel = (suite.object_type && suite.object_type.toLowerCase().includes('suite')) ? 'Suite' : 'Unit';
|
||
suiteDisplay = `<span style="color: #666;">${unitLabel}: ${suite.suite.trim()}</span><br>`;
|
||
}
|
||
|
||
const popupContent = `
|
||
<div style="font-size: 12px; line-height: 1.4; min-width: 160px;">
|
||
<b>🏠 ${props.address}</b><br>
|
||
${suiteDisplay}
|
||
${props.neighborhood ? `<span style="color: #666;">📍 ${props.neighborhood}</span><br>` : ''}
|
||
${suite.object_type ? `<span style="color: #888; font-size: 11px;">${suite.object_type}</span><br>` : ''}
|
||
<small style="color: #888;">City of Edmonton Data</small>
|
||
<div style="margin-top: 8px; padding-top: 8px; border-top: 1px solid #e9ecef;">
|
||
<button class="add-to-database-btn"
|
||
data-address="${props.address}"
|
||
data-lat="${props.lat}"
|
||
data-lng="${props.lng}"
|
||
data-neighborhood="${props.neighborhood || ''}"
|
||
data-suite="${suite.suite || ''}"
|
||
data-object-type="${suite.object_type || ''}"
|
||
style="background: #28a745; color: white; border: none; padding: 4px 8px; border-radius: 3px; font-size: 11px; cursor: pointer; width: 100%;">
|
||
➕ Add to Database
|
||
</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
layer.bindPopup(popupContent, {
|
||
maxWidth: 200,
|
||
closeButton: true
|
||
});
|
||
|
||
// Add event listener for popup open to attach button listeners
|
||
layer.on('popupopen', function(e) {
|
||
setupSingleUnitPopupListeners();
|
||
});
|
||
}
|
||
}
|
||
});
|
||
|
||
edmontonParcelsLayer.addLayer(geoJsonLayer);
|
||
map.addLayer(edmontonParcelsLayer);
|
||
|
||
// Update tracking variables
|
||
lastBounds = expandedBounds;
|
||
lastZoom = currentZoom;
|
||
|
||
const statusMessage = result.data.metadata?.hasMore
|
||
? `Loaded ${result.data.features.length} addresses (more available at higher zoom)`
|
||
: `Loaded ${result.data.features.length} Edmonton addresses`;
|
||
console.log(statusMessage);
|
||
} else {
|
||
throw new Error(result.error || 'Could not load layer data.');
|
||
}
|
||
} catch (error) {
|
||
console.error('Error loading Edmonton parcels layer:', error);
|
||
// Only show error status, not success messages
|
||
showStatus(error.message, 'error');
|
||
} finally {
|
||
isLoading = false;
|
||
if (toggleBtn) toggleBtn.disabled = false;
|
||
if (mobileToggleBtn) mobileToggleBtn.disabled = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Handle map move events
|
||
*/
|
||
function onMapMoveEnd() {
|
||
// Debounce the loading to avoid too many requests
|
||
clearTimeout(onMapMoveEnd.timeout);
|
||
onMapMoveEnd.timeout = setTimeout(() => {
|
||
loadEdmontonData();
|
||
}, 500);
|
||
}
|
||
|
||
/**
|
||
* Handle map zoom events
|
||
*/
|
||
function onMapZoomEnd() {
|
||
// Force reload on zoom change
|
||
loadEdmontonData(true);
|
||
}
|
||
|
||
/**
|
||
* Creates an apartment-style popup for multi-unit buildings
|
||
*/
|
||
function createApartmentPopup(props) {
|
||
const suites = props.suites || [];
|
||
const totalSuites = suites.length;
|
||
|
||
const popupId = `apartment-popup-${Math.random().toString(36).substr(2, 9)}`;
|
||
|
||
// Truncate address if too long for mobile
|
||
const displayAddress = props.address.length > 30 ?
|
||
props.address.substring(0, 30) + '...' : props.address;
|
||
|
||
const popupContent = `
|
||
<div class="apartment-building-popup" data-popup-id="${popupId}" style="font-family: Arial, sans-serif;">
|
||
<div class="building-header">
|
||
<div style="display: flex; align-items: center; justify-content: space-between; gap: 8px;">
|
||
<div style="flex: 1; min-width: 0;">
|
||
<div style="font-weight: bold; font-size: 15px; margin-bottom: 2px; line-height: 1.3;" title="${props.address}">🏢 ${displayAddress}</div>
|
||
<div style="font-size: 12px; opacity: 0.9; line-height: 1.2;">${totalSuites} units • ${props.neighborhood || 'Edmonton'}</div>
|
||
</div>
|
||
<div style="background: rgba(255,255,255,0.25); padding: 4px 8px; border-radius: 10px; font-size: 10px; font-weight: 500; white-space: nowrap;">
|
||
Apt
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="suite-navigator" style="margin-bottom: 12px;">
|
||
<div style="margin-bottom: 6px;">
|
||
<label style="font-size: 11px; color: #666; display: block; margin-bottom: 3px;">
|
||
Suite (${totalSuites} total):
|
||
</label>
|
||
<select class="suite-selector" style="width: 100%; padding: 6px; border: 1px solid #ddd; border-radius: 4px; font-size: 11px; background: white; cursor: pointer;">
|
||
${suites
|
||
.map((suite, originalIndex) => ({ ...suite, originalIndex }))
|
||
.sort((a, b) => {
|
||
// Extract numeric part for sorting
|
||
const aNum = a.suite ? parseInt(a.suite.replace(/\D/g, '')) || 0 : a.originalIndex;
|
||
const bNum = b.suite ? parseInt(b.suite.replace(/\D/g, '')) || 0 : b.originalIndex;
|
||
return aNum - bNum;
|
||
})
|
||
.map((suite) => {
|
||
const displayName = suite.suite ? suite.suite.trim() : `Unit ${suite.originalIndex + 1}`;
|
||
const objectType = suite.object_type || 'Residential';
|
||
// Truncate option text for mobile
|
||
const optionText = `${displayName} (${objectType})`;
|
||
const truncatedText = optionText.length > 25 ?
|
||
optionText.substring(0, 25) + '...' : optionText;
|
||
return `<option value="${suite.originalIndex}" title="${optionText}">${truncatedText}</option>`;
|
||
}).join('')}
|
||
</select>
|
||
</div>
|
||
|
||
<div class="suite-content" style="min-height: 70px; padding: 8px; background: #f8f9fa; border-radius: 4px; border-left: 3px solid #ff6b35;">
|
||
<div class="suite-details">
|
||
<div style="font-weight: bold; font-size: 13px; color: #333; margin-bottom: 3px;">
|
||
${suites[0].suite ? `Suite ${suites[0].suite.trim()}` : `Unit 1`}
|
||
</div>
|
||
<div style="font-size: 11px; color: #666; margin-bottom: 4px;">
|
||
${suites[0].object_type || 'Residential Unit'}
|
||
</div>
|
||
${suites[0].house_number && suites[0].street_name ? `
|
||
<div style="font-size: 10px; color: #888; margin-bottom: 3px;">
|
||
📍 ${suites[0].house_number} ${suites[0].street_name}
|
||
</div>` : ''}
|
||
${suites[0].record_id ? `
|
||
<div style="font-size: 9px; color: #888;">
|
||
ID: ${suites[0].record_id}
|
||
</div>` : ''}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="text-align: center; font-size: 9px; color: #888; border-top: 1px solid #e9ecef; padding-top: 6px; margin-top: 10px;">
|
||
City of Edmonton Open Data
|
||
</div>
|
||
|
||
<div style="margin-top: 6px; padding-top: 6px; border-top: 1px solid #e9ecef;">
|
||
<button class="add-apartment-to-database-btn"
|
||
data-address="${props.address}"
|
||
data-lat="${props.lat}"
|
||
data-lng="${props.lng}"
|
||
data-neighborhood="${props.neighborhood || ''}"
|
||
data-suites='${JSON.stringify(suites)}'
|
||
style="background: #28a745; color: white; border: none; padding: 6px 10px; border-radius: 4px; font-size: 10px; cursor: pointer; width: 100%; font-weight: 500;">
|
||
➕ Add Building to Database
|
||
</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
return popupContent;
|
||
}
|
||
|
||
/**
|
||
* Sets up event listeners for apartment popup suite selection
|
||
*/
|
||
function setupApartmentPopupListeners(props) {
|
||
const suites = props.suites || [];
|
||
|
||
// Find the popup container in the DOM
|
||
const container = document.querySelector('.apartment-building-popup');
|
||
if (!container) {
|
||
console.log('Apartment popup container not found');
|
||
return;
|
||
}
|
||
|
||
const suiteSelector = container.querySelector('.suite-selector');
|
||
const suiteDetails = container.querySelector('.suite-details');
|
||
|
||
if (!suiteSelector || !suiteDetails) {
|
||
console.log('Apartment popup elements not found');
|
||
return;
|
||
}
|
||
|
||
function updateSuiteDisplay(selectedIndex) {
|
||
const suite = suites[selectedIndex];
|
||
|
||
// Better logic for displaying unit/suite information
|
||
let unitLabel = 'Unit';
|
||
let unitNumber = suite.suite ? suite.suite.trim() : '';
|
||
|
||
// If no suite number but has object type that suggests it's a suite
|
||
if (!unitNumber && suite.object_type && suite.object_type.toLowerCase().includes('suite')) {
|
||
unitNumber = `${selectedIndex + 1}`;
|
||
}
|
||
|
||
// If still no unit number, use sequential numbering
|
||
if (!unitNumber) {
|
||
unitNumber = `${selectedIndex + 1}`;
|
||
}
|
||
|
||
// Determine if it's a suite or unit based on the data
|
||
if (suite.object_type && suite.object_type.toLowerCase().includes('suite')) {
|
||
unitLabel = 'Suite';
|
||
}
|
||
|
||
suiteDetails.innerHTML = `
|
||
<div style="font-weight: bold; font-size: 14px; color: #333; margin-bottom: 4px;">
|
||
${unitLabel} ${unitNumber}
|
||
</div>
|
||
<div style="font-size: 12px; color: #666; margin-bottom: 6px;">
|
||
${suite.object_type || 'Residential Unit'}
|
||
</div>
|
||
${suite.house_number && suite.street_name ? `
|
||
<div style="font-size: 11px; color: #888; margin-bottom: 4px;">
|
||
📍 ${suite.house_number} ${suite.street_name}
|
||
</div>` : ''}
|
||
${suite.record_id ? `
|
||
<div style="font-size: 10px; color: #888;">
|
||
ID: ${suite.record_id}
|
||
</div>` : ''}
|
||
`;
|
||
}
|
||
|
||
// Set up suite selector dropdown event listener
|
||
suiteSelector.addEventListener('change', (e) => {
|
||
e.stopPropagation();
|
||
const selectedIndex = parseInt(e.target.value);
|
||
console.log('Suite selected:', selectedIndex);
|
||
updateSuiteDisplay(selectedIndex);
|
||
});
|
||
|
||
// Initialize with first suite selected
|
||
updateSuiteDisplay(0);
|
||
|
||
console.log(`Apartment popup suite selector set up for ${suites.length} suites`);
|
||
|
||
// Set up the "Add to Database" button listener for apartments
|
||
const addBtn = container.querySelector('.add-apartment-to-database-btn');
|
||
if (addBtn) {
|
||
addBtn.addEventListener('click', (e) => {
|
||
e.stopPropagation();
|
||
const address = addBtn.getAttribute('data-address');
|
||
const lat = parseFloat(addBtn.getAttribute('data-lat'));
|
||
const lng = parseFloat(addBtn.getAttribute('data-lng'));
|
||
const neighborhood = addBtn.getAttribute('data-neighborhood');
|
||
const suitesData = JSON.parse(addBtn.getAttribute('data-suites') || '[]');
|
||
|
||
// Get the currently selected suite from dropdown
|
||
const selectedSuiteIndex = parseInt(suiteSelector.value);
|
||
const selectedSuite = suitesData[selectedSuiteIndex] || suitesData[0];
|
||
|
||
// Close the popup first
|
||
map.closePopup();
|
||
|
||
// Open the add modal but prevent the automatic address lookup
|
||
openAddModal(lat, lng, false);
|
||
|
||
// Pre-fill the form with Edmonton data, focusing on the selected suite
|
||
setTimeout(() => {
|
||
prefillAddForm({
|
||
address: address,
|
||
neighborhood: neighborhood,
|
||
lat: lat,
|
||
lng: lng,
|
||
suite: selectedSuite.suite || '',
|
||
objectType: selectedSuite.object_type || '',
|
||
notes: `Selected unit from multi-unit building (${suitesData.length} total units). Imported from City of Edmonton data.`,
|
||
isMultiUnit: true,
|
||
suites: suitesData,
|
||
selectedSuite: selectedSuite
|
||
});
|
||
}, 100);
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Sets up event listeners for single unit popup "Add to Database" button
|
||
*/
|
||
function setupSingleUnitPopupListeners() {
|
||
// Wait for popup to be rendered in DOM
|
||
setTimeout(() => {
|
||
const addBtn = document.querySelector('.add-to-database-btn');
|
||
if (addBtn) {
|
||
addBtn.addEventListener('click', (e) => {
|
||
e.stopPropagation();
|
||
const address = addBtn.getAttribute('data-address');
|
||
const lat = parseFloat(addBtn.getAttribute('data-lat'));
|
||
const lng = parseFloat(addBtn.getAttribute('data-lng'));
|
||
const neighborhood = addBtn.getAttribute('data-neighborhood');
|
||
const suite = addBtn.getAttribute('data-suite');
|
||
const objectType = addBtn.getAttribute('data-object-type');
|
||
|
||
// Close the popup first
|
||
map.closePopup();
|
||
|
||
// Open the add modal but prevent the automatic address lookup
|
||
openAddModal(lat, lng, false);
|
||
|
||
// Pre-fill the form with Edmonton data
|
||
setTimeout(() => {
|
||
prefillAddForm({
|
||
address: address,
|
||
neighborhood: neighborhood,
|
||
lat: lat,
|
||
lng: lng,
|
||
suite: suite,
|
||
objectType: objectType,
|
||
notes: `Imported from City of Edmonton data.${objectType ? ` (${objectType})` : ''}`,
|
||
isMultiUnit: false
|
||
});
|
||
}, 100);
|
||
});
|
||
}
|
||
}, 50);
|
||
}
|
||
|
||
/**
|
||
* Pre-fills the add location form with city data
|
||
*/
|
||
async function prefillAddForm(data) {
|
||
try {
|
||
// Import UI controls dynamically to avoid circular dependencies
|
||
const { resetAddressConfirmation } = await import('./ui-controls.js');
|
||
|
||
// First, reset any existing state
|
||
resetAddressConfirmation('add');
|
||
|
||
// Basic form fields
|
||
if (data.address) {
|
||
const addressField = document.getElementById('location-address');
|
||
if (addressField) {
|
||
addressField.value = data.address;
|
||
}
|
||
}
|
||
|
||
// Put suite number in the unit field
|
||
if (data.suite && data.suite.trim()) {
|
||
const unitField = document.getElementById('location-unit');
|
||
if (unitField) {
|
||
unitField.value = data.suite.trim();
|
||
}
|
||
}
|
||
|
||
// Notes field with additional context
|
||
const notesField = document.getElementById('location-notes');
|
||
if (notesField) {
|
||
let notes = data.notes || '';
|
||
|
||
// Add neighborhood information if available
|
||
if (data.neighborhood && data.neighborhood.trim()) {
|
||
notes += `\nNeighborhood: ${data.neighborhood}`;
|
||
}
|
||
|
||
// Add object type if available
|
||
if (data.objectType && data.objectType.trim()) {
|
||
notes += `\nUnit Type: ${data.objectType}`;
|
||
}
|
||
|
||
// For multi-unit buildings, add information about the selected suite
|
||
if (data.isMultiUnit && data.selectedSuite) {
|
||
notes += `\nSelected Suite: ${data.selectedSuite.suite || 'N/A'}`;
|
||
notes += `\nSuite Type: ${data.selectedSuite.object_type || 'N/A'}`;
|
||
}
|
||
// For single units, add basic suite information
|
||
else if (data.suite && data.suite.trim()) {
|
||
notes += `\nSuite: ${data.suite}`;
|
||
}
|
||
|
||
notesField.value = notes.trim();
|
||
}
|
||
|
||
// Set coordinates (already set by openAddModal, but ensure they're correct)
|
||
const latField = document.getElementById('location-lat');
|
||
const lngField = document.getElementById('location-lng');
|
||
const geoField = document.getElementById('geo-location');
|
||
|
||
if (latField && data.lat) {
|
||
latField.value = data.lat.toFixed(8);
|
||
}
|
||
if (lngField && data.lng) {
|
||
lngField.value = data.lng.toFixed(8);
|
||
}
|
||
if (geoField && data.lat && data.lng) {
|
||
geoField.value = `${data.lat.toFixed(8)};${data.lng.toFixed(8)}`;
|
||
}
|
||
|
||
// Mark the address as confirmed since it's coming from a trusted source
|
||
const { setAddressConfirmed } = await import('./ui-controls.js');
|
||
setAddressConfirmed('add', true);
|
||
|
||
console.log('Form pre-filled and confirmed with city data:', data);
|
||
|
||
} catch (error) {
|
||
console.error('Error pre-filling form:', error);
|
||
showStatus('Error pre-filling form with city data', 'error');
|
||
}
|
||
}
|