oramap/frontend/public/script.js
dvirlabs 016d58ac75
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Add comprehensive logging for add family functionality
- Backend: Log all requests with timestamps
- Backend: Log POST /api/families with validation details
- Frontend: Log fetch requests and responses
- Frontend: Better error messages with status codes
- Frontend: Handle non-JSON responses gracefully
2026-03-25 11:23:05 +02:00

227 lines
6.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

let map = L.map('map').setView([15.5527, 48.5164], 6);
// Define the two tile layers
const voyager = L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', {
attribution: '© OpenStreetMap contributors © CARTO',
subdomains: 'abcd',
maxZoom: 19
});
const openStreetMap = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap contributors',
maxZoom: 19
});
// Add the default layer (Voyager)
voyager.addTo(map);
// Group the layers for switching
const baseMaps = {
"English Map (CartoDB Voyager)": voyager,
"Original Map (OpenStreetMap)": openStreetMap
};
// Add the layer control to the map
L.control.layers(baseMaps).addTo(map);
async function searchFamily() {
const familyName = document.getElementById('searchInput').value.trim();
if (!familyName) {
alert('Please enter a family name.');
return;
}
try {
const response = await fetch(`/api/search?family=${encodeURIComponent(familyName)}`);
const familyResult = await response.json();
if (!familyResult.length) {
alert('No matching family found.');
return;
}
clearMarkers();
familyResult.forEach(record => {
L.marker([record.lat, record.lng]).addTo(map)
.bindPopup(`<strong>${record.family}</strong><br>City: ${record.city}`)
.openPopup();
});
const first = familyResult[0];
map.setView([first.lat, first.lng], 7);
} catch (error) {
console.error('Search error:', error);
alert('Something went wrong while searching. Please try again later.');
}
}
function clearMarkers() {
map.eachLayer(layer => {
if (layer instanceof L.Marker) {
map.removeLayer(layer);
}
});
}
const familyNames = [
"Kafe (קאפח)", "Shiheb (שחב-שבח)", "Eraki (עראקי)", "Salumi (סלומי-שלומי)",
"Afgin (עפג'ין)", "Uzeyri (עזירי-עוזרי)"
// Add more families here if you like
];
// Initialize Fuse.js
const fuse = new Fuse(familyNames, {
includeScore: true,
threshold: 0.4 // Lower = stricter matching
});
const searchInput = document.getElementById('searchInput');
const suggestionsBox = document.createElement('div');
suggestionsBox.classList.add('suggestions');
searchInput.parentNode.style.position = 'relative'; // Make parent relative
searchInput.parentNode.appendChild(suggestionsBox);
searchInput.addEventListener('input', () => {
const value = searchInput.value.trim();
suggestionsBox.innerHTML = '';
if (!value) return;
const results = fuse.search(value);
results.forEach(result => {
const option = document.createElement('div');
option.textContent = result.item;
option.onclick = () => {
searchInput.value = result.item;
suggestionsBox.innerHTML = '';
};
suggestionsBox.appendChild(option);
});
});
L.control.logo = function (opts) {
return new L.Control.Logo(opts);
};
L.Control.Logo = L.Control.extend({
onAdd: function () {
const div = L.DomUtil.create('div', 'custom-logo');
div.innerHTML = `
<img src="logo.png" alt="Logo" style="height: 40px; vertical-align: middle;">
<span style="margin-left: 8px; font-weight: bold; color: #333;">Shevach</span>
`;
return div;
},
onRemove: function () {
// Nothing to clean up
}
});
L.control.logo({ position: 'bottomleft' }).addTo(map);
// Add Family Form Functions
function toggleAddFamilyForm() {
const modal = document.getElementById('addFamilyModal');
const form = document.getElementById('addFamilyForm');
const message = document.getElementById('formMessage');
if (modal.style.display === 'block') {
modal.style.display = 'none';
form.reset();
message.textContent = '';
message.className = 'form-message';
} else {
modal.style.display = 'block';
}
}
async function addFamily(event) {
event.preventDefault();
const familyName = document.getElementById('familyName').value.trim();
const cityName = document.getElementById('cityName').value.trim();
const latitude = parseFloat(document.getElementById('latitude').value);
const longitude = parseFloat(document.getElementById('longitude').value);
const messageEl = document.getElementById('formMessage');
messageEl.textContent = 'Adding family...';
messageEl.className = 'form-message info';
console.log('📝 Adding family:', { familyName, cityName, latitude, longitude });
try {
console.log('🌐 Sending POST request to /api/families');
const response = await fetch('/api/families', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
family: familyName,
city: cityName,
lat: latitude,
lng: longitude
})
});
console.log('📡 Response status:', response.status, response.statusText);
console.log('📡 Response headers:', Object.fromEntries(response.headers.entries()));
const contentType = response.headers.get('content-type');
let data;
if (contentType && contentType.includes('application/json')) {
data = await response.json();
console.log('📦 Response data:', data);
} else {
const text = await response.text();
console.error('⚠️ Non-JSON response:', text);
data = { error: 'Server returned non-JSON response', details: text.substring(0, 200) };
}
if (response.ok) {
console.log('✅ Family added successfully!');
messageEl.textContent = '✅ Family added successfully!';
messageEl.className = 'form-message success';
// Add marker to map
L.marker([latitude, longitude]).addTo(map)
.bindPopup(`<strong>${familyName}</strong><br>City: ${cityName}`)
.openPopup();
map.setView([latitude, longitude], 10);
// Reset form after 2 seconds
setTimeout(() => {
toggleAddFamilyForm();
}, 2000);
} else {
console.error('❌ Server error:', data);
messageEl.textContent = `❌ Error (${response.status}): ${data.error || data.message || 'Unknown error'}`;
messageEl.className = 'form-message error';
}
} catch (error) {
console.error('❌ Add family error:', error);
messageEl.textContent = `❌ Failed: ${error.message || 'Network error'}`;
messageEl.className = 'form-message error';
}
}
// Close modal when clicking outside
window.onclick = function(event) {
const modal = document.getElementById('addFamilyModal');
if (event.target === modal) {
toggleAddFamilyForm();
}
}
// Allow Enter key to trigger search
document.getElementById('searchInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
searchFamily();
}
});