up source events

This commit is contained in:
Tykayn 2025-09-21 19:18:43 +02:00 committed by tykayn
parent 7971e48636
commit f18383fb9e
3 changed files with 489 additions and 27 deletions

View file

@ -63,22 +63,111 @@
</div>
<h3>Select Issue Type</h3>
<div class="issue-buttons">
<div class="issue-button pothole" onclick="fillForm('pothole')">
<i class="fas fa-dot-circle"></i>
Pothole
<!-- Tab Navigation -->
<div class="tabs">
<div class="tab-item active" data-tab="road">
<i class="fas fa-road"></i> Road
</div>
<div class="issue-button obstacle" onclick="fillForm('obstacle')">
<i class="fas fa-exclamation-triangle"></i>
Obstacle
<div class="tab-item" data-tab="rail">
<i class="fas fa-train"></i> Rail
</div>
<div class="issue-button vehicle" onclick="fillForm('vehicle')">
<i class="fas fa-car"></i>
Vehicle on Side
<div class="tab-item" data-tab="weather">
<i class="fas fa-cloud-sun-rain"></i> Weather
</div>
<div class="issue-button danger" onclick="fillForm('danger')">
<i class="fas fa-skull-crossbones"></i>
Danger
<div class="tab-item" data-tab="emergency">
<i class="fas fa-exclamation-circle"></i> Emergency
</div>
</div>
<!-- Tab Content -->
<div class="tab-content">
<!-- Road Tab -->
<div class="tab-pane active" id="road-tab">
<div class="issue-buttons">
<div class="issue-button road pothole" onclick="fillForm('pothole')">
<i class="fas fa-dot-circle"></i>
Pothole
</div>
<div class="issue-button road obstacle" onclick="fillForm('obstacle')">
<i class="fas fa-exclamation-triangle"></i>
Obstacle
</div>
<div class="issue-button road vehicle" onclick="fillForm('vehicle')">
<i class="fas fa-car"></i>
Vehicle on Side
</div>
<div class="issue-button road danger" onclick="fillForm('danger')">
<i class="fas fa-skull-crossbones"></i>
Danger
</div>
<div class="issue-button road accident" onclick="fillForm('accident')">
<i class="fas fa-car-crash"></i>
Accident
</div>
<div class="issue-button road flooded-road" onclick="fillForm('flooded_road')">
<i class="fas fa-water"></i>
Flooded Road
</div>
<div class="issue-button road roadwork" onclick="fillForm('roadwork')">
<i class="fas fa-hard-hat"></i>
Roadwork
</div>
<div class="issue-button road black-traffic" onclick="fillForm('black_traffic')">
<i class="fas fa-traffic-light"></i>
Black Traffic
</div>
</div>
</div>
<!-- Rail Tab -->
<div class="tab-pane" id="rail-tab">
<div class="issue-buttons">
<div class="issue-button rail unattended-luggage" onclick="fillForm('unattended_luggage')">
<i class="fas fa-suitcase"></i>
Unattended Luggage
</div>
<div class="issue-button rail transport-delay" onclick="fillForm('transport_delay')">
<i class="fas fa-hourglass-half"></i>
Delay
</div>
<div class="issue-button rail major-delay" onclick="fillForm('major_transport_delay')">
<i class="fas fa-hourglass-end"></i>
Major Delay
</div>
</div>
</div>
<!-- Weather Tab -->
<div class="tab-pane" id="weather-tab">
<div class="issue-buttons">
<div class="issue-button weather flood-danger" onclick="fillForm('flood_danger')">
<i class="fas fa-water"></i>
Flood Alert
</div>
<div class="issue-button weather thunderstorm" onclick="fillForm('thunderstorm_alert')">
<i class="fas fa-bolt"></i>
Thunderstorm
</div>
<div class="issue-button weather fog" onclick="fillForm('fog_warning')">
<i class="fas fa-smog"></i>
Fog Warning
</div>
</div>
</div>
<!-- Emergency Tab -->
<div class="tab-pane" id="emergency-tab">
<div class="issue-buttons">
<div class="issue-button emergency emergency-alert" onclick="fillForm('emergency_alert')">
<i class="fas fa-exclamation-circle"></i>
Emergency Alert
</div>
<div class="issue-button emergency daylight-saving" onclick="fillForm('daylight_saving')">
<i class="fas fa-clock"></i>
Daylight Saving
</div>
</div>
</div>
</div>
@ -134,7 +223,7 @@
<div class="note">Click on the map to set the issue location or use the "Get My Current Location" button</div>
</div>
<button type="submit">Report Issue</button>
<button id="report_issue_button" type="submit" disabled>Report Issue</button>
</form>
<div id="result"></div>
@ -161,6 +250,49 @@
// Call function to set default dates
setDefaultDates();
// Tab switching functionality
document.addEventListener('DOMContentLoaded', function() {
// Get all tab items
const tabItems = document.querySelectorAll('.tab-item');
// Add click event listener to each tab item
tabItems.forEach(tab => {
tab.addEventListener('click', function() {
// Remove active class from all tab items
tabItems.forEach(item => item.classList.remove('active'));
// Add active class to clicked tab item
this.classList.add('active');
// Get the tab name from data-tab attribute
const tabName = this.getAttribute('data-tab');
// Get all tab panes
const tabPanes = document.querySelectorAll('.tab-pane');
// Remove active class from all tab panes
tabPanes.forEach(pane => pane.classList.remove('active'));
// Add active class to the corresponding tab pane
document.getElementById(tabName + '-tab').classList.add('active');
// Save active tab to localStorage
localStorage.setItem('activeTab', tabName);
});
});
// Restore active tab from localStorage
const activeTab = localStorage.getItem('activeTab');
if (activeTab) {
// Find the tab item with the saved tab name
const tabItem = document.querySelector(`.tab-item[data-tab="${activeTab}"]`);
if (tabItem) {
// Trigger click event on the tab item
tabItem.click();
}
}
});
// Initialize the map
const map = new maplibregl.Map({
container: 'map',
@ -168,15 +300,73 @@
center: [2.2137, 46.2276], // Default center (center of metropolitan France)
zoom: 5
});
// Add navigation controls
map.addControl(new maplibregl.NavigationControl());
// Add marker for issue location
let marker = new maplibregl.Marker({
draggable: true,
color: '#ff3860' // Red color for traffic jam
});
// Store existing traffic event markers
let existingMarkers = [];
// Function to fetch and display existing traffic events
function fetchExistingTrafficEvents() {
// Clear existing markers first
existingMarkers.forEach(marker => marker.remove());
existingMarkers = [];
// Fetch traffic events from the API
fetch('https://api.openeventdatabase.org/event?what=traffic')
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Failed to fetch existing traffic events');
}
})
.then(data => {
if (data && data.features && Array.isArray(data.features)) {
// Add markers for each event
data.features.forEach(event => {
if (event.geometry && event.geometry.type === 'Point') {
const coords = event.geometry.coordinates;
// Create a gray marker for existing events
const eventMarker = new maplibregl.Marker({
color: '#888888' // Gray color for existing events
})
.setLngLat(coords)
.addTo(map);
// Add popup with event details
const popup = new maplibregl.Popup({ offset: 25 })
.setHTML(`
<h3>${event.properties.label || 'Traffic Event'}</h3>
<p>Type: ${event.properties.what || 'Unknown'}</p>
<p>Start: ${event.properties.start || 'Unknown'}</p>
<p>End: ${event.properties.stop || 'Unknown'}</p>
`);
eventMarker.setPopup(popup);
// Store marker reference for later removal
existingMarkers.push(eventMarker);
}
});
console.log(`Loaded ${existingMarkers.length} existing traffic events`);
}
})
.catch(error => {
console.error('Error fetching traffic events:', error);
});
}
// Fetch existing events when the map loads
map.on('load', fetchExistingTrafficEvents);
// Add marker on map click
map.on('click', function(e) {
@ -201,28 +391,100 @@
switch(issueType) {
case 'pothole':
labelInput.value = 'Nid de poule';
issueTypeInput.value = 'road.hazard.pothole';
issueTypeInput.value = 'traffic.hazard.pothole';
severitySelect.value = 'medium';
markerColor = '#ff9800';
break;
case 'obstacle':
labelInput.value = 'Obstacle';
issueTypeInput.value = 'road.hazard.obstacle';
issueTypeInput.value = 'traffic.hazard.obstacle';
severitySelect.value = 'high';
markerColor = '#f44336';
break;
case 'vehicle':
labelInput.value = 'Véhicule sur le bas côté de la route';
issueTypeInput.value = 'road.hazard.vehicle';
issueTypeInput.value = 'traffic.hazard.vehicle';
severitySelect.value = 'low';
markerColor = '#2196f3';
break;
case 'danger':
labelInput.value = 'Danger non classé';
issueTypeInput.value = 'road.hazard.danger';
issueTypeInput.value = 'traffic.hazard.danger';
severitySelect.value = 'high';
markerColor = '#9c27b0';
break;
case 'emergency_alert':
labelInput.value = 'Alerte d\'urgence (SAIP)';
issueTypeInput.value = 'alert.emergency';
severitySelect.value = 'high';
markerColor = '#e91e63'; // Pink
break;
case 'daylight_saving':
labelInput.value = 'Période d\'heure d\'été';
issueTypeInput.value = 'time.daylight.summer';
severitySelect.value = 'low';
markerColor = '#ffc107'; // Amber
break;
case 'accident':
labelInput.value = 'Accident de la route';
issueTypeInput.value = 'traffic.accident';
severitySelect.value = 'high';
markerColor = '#d32f2f'; // Dark red
break;
case 'flooded_road':
labelInput.value = 'Route inondée';
issueTypeInput.value = 'traffic.closed.flood';
severitySelect.value = 'high';
markerColor = '#1976d2'; // Blue
break;
case 'black_traffic':
labelInput.value = 'Période noire bison futé vers la province';
issueTypeInput.value = 'traffic.forecast.black.out';
severitySelect.value = 'high';
markerColor = '#212121'; // Black
break;
case 'roadwork':
labelInput.value = 'Travaux';
issueTypeInput.value = 'traffic.roadwork';
severitySelect.value = 'medium';
markerColor = '#ff5722'; // Deep orange
break;
case 'flood_danger':
labelInput.value = 'Vigilance rouge inondation';
issueTypeInput.value = 'weather.danger.flood';
severitySelect.value = 'high';
markerColor = '#b71c1c'; // Dark red
break;
case 'thunderstorm_alert':
labelInput.value = 'Vigilance orange orages';
issueTypeInput.value = 'weather.alert.thunderstorm';
severitySelect.value = 'medium';
markerColor = '#ff9800'; // Orange
break;
case 'fog_warning':
labelInput.value = 'Vigilance jaune brouillard';
issueTypeInput.value = 'weather.warning.fog';
severitySelect.value = 'low';
markerColor = '#ffeb3b'; // Yellow
break;
case 'unattended_luggage':
labelInput.value = 'Bagage abandonné';
issueTypeInput.value = 'public_transport.incident.unattended_luggage';
severitySelect.value = 'medium';
markerColor = '#673ab7'; // Deep purple
break;
case 'transport_delay':
labelInput.value = 'Retard';
issueTypeInput.value = 'public_transport.delay';
severitySelect.value = 'low';
markerColor = '#ffc107'; // Amber
break;
case 'major_transport_delay':
labelInput.value = 'Retard important';
issueTypeInput.value = 'public_transport.delay.major';
severitySelect.value = 'medium';
markerColor = '#ff5722'; // Deep orange
break;
default:
labelInput.value = 'Bouchon';
issueTypeInput.value = 'traffic.jam';
@ -240,6 +502,9 @@
if (currentLngLat) {
marker.setLngLat(currentLngLat).addTo(map);
}
// Validate form after filling in values
validateForm();
}
// Handle geolocation button click
@ -272,6 +537,9 @@
// Show success message
showResult('Current location detected successfully', 'success');
// Validate form after setting marker
validateForm();
// Try to get address using reverse geocoding
fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}`)
.then(response => response.json())
@ -341,10 +609,75 @@
}
});
// Form validation function
function validateForm() {
// Get all required form fields
const requiredFields = document.querySelectorAll('#trafficForm [required]');
const submitButton = document.getElementById('report_issue_button');
// Check if all required fields are filled
let isValid = true;
// Check each required field
requiredFields.forEach(field => {
if (!field.value.trim()) {
isValid = false;
}
});
// Check if marker is set
if (!marker || !marker.getLngLat()) {
isValid = false;
}
// Enable or disable submit button based on form validity
submitButton.disabled = !isValid;
// Add or remove disabled class
if (isValid) {
submitButton.classList.remove('disabled');
} else {
submitButton.classList.add('disabled');
}
return isValid;
}
// Add event listeners to form fields to trigger validation
document.addEventListener('DOMContentLoaded', function() {
// Get all form fields
const formFields = document.querySelectorAll('#trafficForm input, #trafficForm select');
// Add input event listener to each field
formFields.forEach(field => {
field.addEventListener('input', validateForm);
});
// Add change event listener to each field
formFields.forEach(field => {
field.addEventListener('change', validateForm);
});
// Validate form on page load
validateForm();
});
// Update validation when marker is set
map.on('click', function() {
// Validate form after marker is set
setTimeout(validateForm, 100);
});
// Handle form submission
document.getElementById('trafficForm').addEventListener('submit', function(e) {
e.preventDefault();
// Validate form before submission
if (!validateForm()) {
showResult('Please fill in all required fields and set a location on the map', 'error');
return;
}
// Get form values
const label = document.getElementById('label').value;
const issueType = document.getElementById('issueType').value;
@ -354,7 +687,7 @@
const stop = document.getElementById('stop').value;
const where = document.getElementById('where').value;
// Check if marker is set
// Check if marker is set (redundant but kept for safety)
if (!marker.getLngLat()) {
showResult('Please set a location by clicking on the map or using the geolocation button', 'error');
return;
@ -413,7 +746,7 @@
saveEventToLocalStorage(event);
// Submit event to API
fetch('/event', {
fetch('https://api.openeventdatabase.org/event', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
@ -441,7 +774,7 @@
const resultElement = document.getElementById('result');
resultElement.innerHTML += `
<p>
<a href="/event/${data.id}" >View Report on Server</a> |
<a href="https://api.openeventdatabase.org/event/${data.id}" >View Report on Server</a> |
<a href="/demo/view-events" >View Saved Reports</a> |
<a href="/demo">Back to Map</a>
</p>`;
@ -452,6 +785,9 @@
setDefaultDates();
// Remove marker
marker.remove();
// Refresh the map to show the new event along with existing ones
fetchExistingTrafficEvents();
})
.catch(error => {
showResult(`Error reporting issue: ${error.message}`, 'error');