diff --git a/js/main.js b/js/main.js index 3e51915..763a939 100644 --- a/js/main.js +++ b/js/main.js @@ -1,4 +1,16 @@ +// /Volumes/Data/Code/FHGR/Frontend/js/main.js document.addEventListener('DOMContentLoaded', function() { + // Initialize global variables + window.currentJourney = { + id: Date.now(), + name: "Untitled Journey", + description: "", + markers: [], + path: null + }; + window.journeys = []; + window.isCreatingJourney = true; + // Mode switching const modeCreateBtn = document.getElementById('mode-create'); const modeViewBtn = document.getElementById('mode-view'); @@ -28,66 +40,211 @@ document.addEventListener('DOMContentLoaded', function() { modeCreateBtn.addEventListener('click', () => switchMode('create')); modeViewBtn.addEventListener('click', () => switchMode('view')); - // Journey save handler - document.getElementById('save-journey').addEventListener('click', function() { - const title = document.getElementById('journey-title').value; - const description = document.getElementById('journey-description').value; - - if (!title.trim()) { - alert('Journey title cannot be empty'); - return; + async function loadJourneysFromBackend() { + try { + const response = await fetch('http://localhost:5000/api/journeys'); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const journeysData = await response.json(); + + // Ensure we always have an array + if (!Array.isArray(journeysData)) { + console.warn('Expected array of journeys, got:', journeysData); + window.journeys = []; + return []; + } + + window.journeys = journeysData; + populateJourneySelect(journeysData); + return journeysData; + } catch (err) { + console.error('Error loading journeys from backend:', err); + // Fallback to local storage + const savedJourneys = localStorage.getItem('journeys'); + if (savedJourneys) { + try { + const parsedJourneys = JSON.parse(savedJourneys); + if (Array.isArray(parsedJourneys)) { + window.journeys = parsedJourneys; + populateJourneySelect(window.journeys); + return window.journeys; + } else { + console.warn('Saved journeys are not an array:', parsedJourneys); + window.journeys = []; + populateJourneySelect([]); + return []; + } + } catch (parseError) { + console.error('Error parsing saved journeys:', parseError); + window.journeys = []; + populateJourneySelect([]); + return []; + } + } + // If no data available, initialize empty array + window.journeys = []; + populateJourneySelect([]); + return []; } - - window.currentJourney.name = title; - window.currentJourney.description = description; + } - // Add the current journey to the journeys array if not already added - const existingJourneyIndex = window.journeys.findIndex(j => j.id === window.currentJourney.id); - if (existingJourneyIndex === -1) { - window.journeys.push({ - id: window.currentJourney.id, - name: window.currentJourney.name, - description: window.currentJourney.description, - markers: window.currentJourney.markers.map(marker => ({ - id: marker.id, - lngLat: marker.getLngLat(), - content: marker.content - })) + async function saveJourneyToBackend(journey) { + try { + const response = await fetch('http://localhost:5000/api/journeys', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + id: journey.id, + name: journey.name, + description: journey.description, + markers: journey.markers.map(marker => ({ + lngLat: marker.getLngLat().toArray(), + content: marker.content + })) + }) }); - } else { - window.journeys[existingJourneyIndex] = { - ...window.journeys[existingJourneyIndex], - name: window.currentJourney.name, - description: window.currentJourney.description, - markers: window.currentJourney.markers.map(marker => ({ - id: marker.id, - lngLat: marker.getLngLat(), - content: marker.content - })) + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const journeyData = await response.json(); + console.log('Journey saved:', journeyData); + return journeyData; + } catch (err) { + console.error('Error saving journey to backend:', err); + // Fallback to local storage + const savedJourneys = localStorage.getItem('journeys') || '[]'; + const journeys = JSON.parse(savedJourneys); + + // Update or add the journey + const existingIndex = journeys.findIndex(j => j.id === journey.id); + if (existingIndex !== -1) { + journeys[existingIndex] = { + id: journey.id, + name: journey.name, + description: journey.description, + markers: journey.markers.map(marker => ({ + id: marker.id, + lngLat: marker.getLngLat(), + content: marker.content + })) + }; + } else { + journeys.push({ + id: journey.id, + name: journey.name, + description: journey.description, + markers: journey.markers.map(marker => ({ + id: marker.id, + lngLat: marker.getLngLat(), + content: marker.content + })) + }); + } + + localStorage.setItem('journeys', JSON.stringify(journeys)); + console.log('Journey saved to local storage'); + return journey; + } + } + + async function loadCurrentJourneyFromBackend(journeyId) { + try { + const response = await fetch(`http://localhost:5000/api/journeys/${journeyId}`); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const journeyData = await response.json(); + + // Update the current journey object + window.currentJourney = { + id: journeyData.id, + name: journeyData.name, + description: journeyData.description, + markers: [], + path: null }; + + // Create markers from the journey data + if (Array.isArray(journeyData.markers)) { + journeyData.markers.forEach(markerData => { + const lngLat = maplibregl.LngLat.fromArray(markerData.lngLat); + const marker = window.createMarker(lngLat, markerData.content); + window.currentJourney.markers.push(marker); + }); + } + + // Update the journey path + updateJourneyPath(); + + return journeyData; + } catch (err) { + console.error('Error loading journey from backend:', err); + // Fallback to local storage + const savedJourneys = localStorage.getItem('journeys'); + if (savedJourneys) { + try { + const journeys = JSON.parse(savedJourneys); + if (Array.isArray(journeys)) { + const journey = journeys.find(j => j.id === journeyId); + if (journey) { + // Update the current journey object + window.currentJourney = { + id: journey.id, + name: journey.name, + description: journey.description, + markers: [], + path: null + }; + + // Create markers from the journey data + if (Array.isArray(journey.markers)) { + journey.markers.forEach(markerData => { + const lngLat = maplibregl.LngLat.fromArray(markerData.lngLat); + const marker = window.createMarker(lngLat, markerData.content); + window.currentJourney.markers.push(marker); + }); + } + + // Update the journey path + updateJourneyPath(); + + console.log('Journey loaded from local storage'); + return journey; + } + } else { + console.warn('Saved journeys are not an array:', journeys); + } + } catch (parseError) { + console.error('Error parsing saved journeys:', parseError); + } + } + // If no data available, return null + return null; } + } - window.saveJourneyToLocalStorage(); + // Update the journey select dropdown + function populateJourneySelect(journeys) { + const select = document.getElementById('journey-select'); + select.innerHTML = ''; + select.innerHTML += ''; - // Show notification - document.getElementById('toast-message').textContent = 'Journey saved successfully!'; - document.getElementById('toast').classList.add('show'); - setTimeout(() => { - document.getElementById('toast').classList.remove('show'); - }, 3000); - }); + // Sort journeys by name for consistent ordering + const sortedJourneys = [...journeys].sort((a, b) => a.name.localeCompare(b.name)); + + sortedJourneys.forEach(journey => { + const option = document.createElement('option'); + option.value = journey.id; + option.textContent = journey.name; + select.appendChild(option); + }); + } - // Clear markers - document.getElementById('clear-markers').addEventListener('click', function() { - if (window.currentJourney.markers.length > 0 && confirm('Are you sure you want to clear all markers?')) { - window.currentJourney.markers.forEach(marker => marker.remove()); - window.currentJourney.markers = []; - markersContainer.innerHTML = ''; - emptyMarkers.style.display = 'block'; - window.updateJourneyPath(); - } - }); - // Toggle sidebar document.getElementById('toggle-sidebar').addEventListener('click', function() { document.querySelector('.sidebar').classList.toggle('collapsed'); @@ -95,4 +252,127 @@ document.addEventListener('DOMContentLoaded', function() { // Initialize in create mode switchMode('create'); + + // Load journeys from backend when the page loads + loadJourneysFromBackend().then(() => { + // If there are journeys, set the first one as the current journey + if (window.journeys.length > 0) { + // Set the first journey as current + const firstJourney = window.journeys[0]; + loadCurrentJourneyFromBackend(firstJourney.id).then(() => { + // Update the journey title and description + document.getElementById('journey-title').value = currentJourney.name; + document.getElementById('journey-description').value = currentJourney.description; + }); + } + }); + + // Add journey selection functionality + document.getElementById('journey-select').addEventListener('change', function() { + const selectedId = this.value; + + if (selectedId === 'all') { + // Show all journeys + // Implementation depends on how you want to display multiple journeys + return; + } + + if (selectedId) { + // Load the selected journey + loadCurrentJourneyFromBackend(selectedId).then(() => { + // Update the journey title and description + document.getElementById('journey-title').value = currentJourney.name; + document.getElementById('journey-description').value = currentJourney.description; + + // Update the journey info panel + document.getElementById('info-title').textContent = currentJourney.name; + document.getElementById('info-description').textContent = currentJourney.description; + document.getElementById('info-marker-count').textContent = currentJourney.markers.length; + document.getElementById('info-date').textContent = new Date().toLocaleDateString(); + }); + } + }); + + // View blog post button + document.getElementById('view-blog').addEventListener('click', function() { + // Implementation depends on your blog system + alert('Viewing blog post for this journey...'); + }); + + // Edit journey button + document.getElementById('edit-journey').addEventListener('click', function() { + // Switch to create mode + switchMode('create'); + // Update the journey title and description + document.getElementById('journey-title').value = currentJourney.name; + document.getElementById('journey-description').value = currentJourney.description; + }); + + // Delete journey button + document.getElementById('delete-journey').addEventListener('click', async function() { + if (confirm('Are you sure you want to delete this journey?')) { + try { + const response = await fetch(`http://localhost:5000/api/journeys/${currentJourney.id}`, { + method: 'DELETE' + }); + + if (response.ok) { + // Remove from the journeys array + const index = window.journeys.findIndex(j => j.id === currentJourney.id); + if (index !== -1) { + window.journeys.splice(index, 1); + } + + // Update the journey select dropdown + populateJourneySelect(window.journeys); + + // Clear the current journey + currentJourney = { + id: Date.now(), + name: "Untitled Journey", + description: "", + markers: [], + path: null + }; + + // Clear the map + map.getSource('journey-path').setData({ + type: 'Feature', + properties: {}, + geometry: { + type: 'LineString', + coordinates: [] + } + }); + + // Clear the form + document.getElementById('journey-title').value = ''; + document.getElementById('journey-description').value = ''; + + alert('Journey deleted successfully!'); + } else { + alert('Failed to delete journey.'); + } + } catch (err) { + console.error('Error deleting journey:', err); + // Fallback to local storage + const savedJourneys = localStorage.getItem('journeys'); + if (savedJourneys) { + try { + const journeys = JSON.parse(savedJourneys); + if (Array.isArray(journeys)) { + const index = journeys.findIndex(j => j.id === currentJourney.id); + if (index !== -1) { + journeys.splice(index, 1); + localStorage.setItem('journeys', JSON.stringify(journeys)); + } + } + } catch (parseError) { + console.error('Error parsing saved journeys:', parseError); + } + } + alert('Journey deleted successfully (local storage)'); + } + } + }); }); diff --git a/js/map.js b/js/map.js index 7badb91..6042261 100644 --- a/js/map.js +++ b/js/map.js @@ -1,90 +1,76 @@ -let map; -let journeys = []; -let currentJourney = { - id: Date.now(), - name: "Untitled Journey", - description: "", - markers: [], - path: null -}; -let currentMarkerBeingEdited = null; -let isCreatingJourney = true; +// /Volumes/Data/Code/FHGR/Frontend/js/map.js +// Add the createMarker function to the window object +window.createMarker = function(lngLat, content = {}) { + const marker = new maplibregl.Marker({ + color: '#3887be', + draggable: true + }) + .setLngLat(lngLat) + .addTo(map); -function saveJourneyToLocalStorage() { - localStorage.setItem('journeys', JSON.stringify(journeys)); -} - -function loadJourneysFromLocalStorage() { - const stored = localStorage.getItem('journeys'); - if (stored) { - journeys = JSON.parse(stored); - } -} - -// Function to create a marker at a lngLat and add to the map -function createMarker(lngLat) { - const markerElement = document.createElement('div'); - markerElement.className = 'marker'; - markerElement.innerHTML = ''; - - const marker = new maplibregl.Marker(markerElement) - .setLngLat(lngLat) - .addTo(map); - - marker.id = Date.now(); - marker.content = { - title: '', - date: '', - text: '', - images: [], - videoUrl: '' - }; - - // Add a popup + // Create popup with marker content const popup = new maplibregl.Popup({ offset: 25 }) - .setHTML('New Marker'); + .setHTML(`${content.title || 'Untitled'}`); + marker.setPopup(popup); // When the marker is clicked, open the editor - markerElement.addEventListener('click', () => { + marker.getElement().addEventListener('click', () => { openMarkerEditor(marker); }); + // Add marker to current journey + const markerData = { + id: Date.now(), + lngLat: lngLat.toArray(), + content: content + }; + + // Add marker to current journey currentJourney.markers.push(marker); updateJourneyPath(); - return marker; -} - -function openMarkerEditor(marker) { - currentMarkerBeingEdited = marker; - document.getElementById('marker-title').value = marker.content.title || ''; - document.getElementById('marker-date').value = marker.content.date || ''; - document.getElementById('marker-text').value = marker.content.text || ''; - document.getElementById('video-url').value = marker.content.videoUrl || ''; - document.getElementById('marker-coords').textContent = - `${marker.getLngLat().lng.toFixed(4)}, ${marker.getLngLat().lat.toFixed(4)}`; - - // Update image review - const imagePreview = document.getElementById('image-preview'); - imagePreview.innerHTML = ''; - if (marker.content.images && marker.content.images.length > 0) { - marker.content.images.forEach(img => { - const imgEl = document.createElement('img'); - imgEl.src = img; - imagePreview.appendChild(imgEl); + + // Add marker to the markers list + const markersContainer = document.getElementById('markers-container'); + const markerElement = document.createElement('div'); + markerElement.className = 'marker-item'; + markerElement.innerHTML = ` +
${content.title || 'Untitled'}
+
${lngLat.lng.toFixed(4)}, ${lngLat.lat.toFixed(4)}
+ `; + + // Add click event to marker item + markerElement.addEventListener('click', function() { + // Center map on marker + map.flyTo({ + center: lngLat, + zoom: 10 }); - } + + // Open marker editor + openMarkerEditor(marker); + }); + + markersContainer.appendChild(markerElement); + + return marker; +}; - document.getElementById('marker-modal').style.display = 'block'; -} - -function closeMarkerEditor() { - document.getElementById('marker-modal').style.display = 'none'; - currentMarkerBeingEdited = null; -} - -// Function to update the journey path +// Update the updateJourneyPath function to handle cases where markers array is empty function updateJourneyPath() { + if (!currentJourney.markers || currentJourney.markers.length === 0) { + // If no markers, clear the path + map.getSource('journey-path').setData({ + type: 'Feature', + properties: {}, + geometry: { + type: 'LineString', + coordinates: [] + } + }); + return; + } + const coordinates = currentJourney.markers.map(marker => marker.getLngLat().toArray()); map.getSource('journey-path').setData({ @@ -96,126 +82,3 @@ function updateJourneyPath() { } }); } - -document.addEventListener('DOMContentLoaded', function() { - map = new maplibregl.Map({ - container: 'map', - style: 'https://demotiles.maplibre.org/style.json', - center: [0, 20], - zoom: 2 - }); - - // Add journey path layer - map.on('load', function() { - map.addSource('journey-path', { - type: 'geojson', - data: { - type: 'Feature', - properties: {}, - geometry: { - type: 'LineString', - coordinates: [] - } - } - }); - - map.addLayer({ - id: 'journey-path', - type: 'line', - source: 'journey-path', - layout: { - 'line-join': 'round', - 'line-cap': 'round' - }, - paint: { - 'line-color': '#3887be', - 'line-width': 5 - } - }); - }); - - // Close editor events - document.getElementById('close-modal').addEventListener('click', closeMarkerEditor); - document.getElementById('cancel-marker').addEventListener('click', closeMarkerEditor); - - // Save marker event - document.getElementById('save-marker').addEventListener('click', function() { - if (!currentMarkerBeingEdited) return; - - // Update marker content - currentMarkerBeingEdited.content.title = document.getElementById('marker-title').value; - currentMarkerBeingEdited.content.date = document.getElementById('marker-date').value; - currentMarkerBeingEdited.content.text = document.getElementById('marker-text').value; - currentMarkerBeingEdited.content.videoUrl = document.getElementById('video-url').value; - - // Update the popup - currentMarkerBeingEdited.getPopup().setHTML( - `${currentMarkerBeingEdited.content.title || 'Untitled'}` - ); - - closeMarkerEditor(); - }); - - // Delete marker event - document.getElementById('delete-marker').addEventListener('click', function() { - if (!currentMarkerBeingEdited) return; - - // Remove from map - currentMarkerBeingEdited.remove(); - - // Remove from currentJourney.markers - const index = currentJourney.markers.findIndex(m => m.id === currentMarkerBeingEdited.id); - if (index !== -1) { - currentJourney.markers.splice(index, 1); - } - - updateJourneyPath(); // Update path after marker deletion - - closeMarkerEditor(); - }); - - // Add marker on map click - map.on('click', (e) => { - if (isCreatingJourney) { - createMarker(e.lngLat); - } - }); - - // Save journey button - document.getElementById('save-journey').addEventListener('click', function() { - currentJourney.name = document.getElementById('journey-title').value; - currentJourney.description = document.getElementById('journey-description').value; - - // Add the current journey to the journeys array if not already added - const existingJourneyIndex = journeys.findIndex(j => j.id === currentJourney.id); - if (existingJourneyIndex === -1) { - journeys.push({ - id: currentJourney.id, - name: currentJourney.name, - description: currentJourney.description, - markers: currentJourney.markers.map(marker => ({ - id: marker.id, - lngLat: marker.getLngLat(), - content: marker.content - })) - }); - } else { - journeys[existingJourneyIndex] = { - ...journeys[existingJourneyIndex], - name: currentJourney.name, - description: currentJourney.description, - markers: currentJourney.markers.map(marker => ({ - id: marker.id, - lngLat: marker.getLngLat(), - content: marker.content - })) - }; - } - - saveJourneyToLocalStorage(); - alert('Journey saved!'); - }); - - // Load journeys on start - loadJourneysFromLocalStorage(); -});