diff --git a/app/controllers/api/v1/visits/possible_places_controller.rb b/app/controllers/api/v1/visits/possible_places_controller.rb new file mode 100644 index 00000000..0fc76aec --- /dev/null +++ b/app/controllers/api/v1/visits/possible_places_controller.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class Api::V1::Visits::PossiblePlacesController < ApiController + def index + visit = current_api_user.visits.find(params[:id]) + # Assuming you have a method to fetch possible places + possible_places = visit.suggested_places + + render json: possible_places + rescue ActiveRecord::RecordNotFound + render json: { error: 'Visit not found' }, status: :not_found + end +end diff --git a/app/controllers/api/v1/visits_controller.rb b/app/controllers/api/v1/visits_controller.rb index 3c5a773e..057b3e4e 100644 --- a/app/controllers/api/v1/visits_controller.rb +++ b/app/controllers/api/v1/visits_controller.rb @@ -31,7 +31,7 @@ class Api::V1::VisitsController < ApiController visit = current_api_user.visits.find(params[:id]) visit = update_visit(visit) - render json: visit + render json: Api::VisitSerializer.new(visit).call end private diff --git a/app/javascript/controllers/maps_controller.js b/app/javascript/controllers/maps_controller.js index 6b2de7fd..25ef66b2 100644 --- a/app/javascript/controllers/maps_controller.js +++ b/app/javascript/controllers/maps_controller.js @@ -31,6 +31,7 @@ export default class extends BaseController { trackedMonthsCache = null; drawerOpen = false; visitCircles = L.layerGroup(); + currentPopup = null; connect() { super.connect(); @@ -103,6 +104,11 @@ export default class extends BaseController { this.map.getPane('areasPane').style.zIndex = 650; this.map.getPane('areasPane').style.pointerEvents = 'all'; + // Create custom pane for visits + this.map.createPane('visitsPane'); + this.map.getPane('visitsPane').style.zIndex = 600; + this.map.getPane('visitsPane').style.pointerEvents = 'all'; + // Initialize areasLayer as a feature group and add it to the map immediately this.areasLayer = new L.FeatureGroup(); this.photoMarkers = L.layerGroup(); @@ -1382,7 +1388,7 @@ export default class extends BaseController { drawerButton.innerHTML = this.drawerOpen ? '➡️' : '⬅️'; } - const controls = document.querySelectorAll('.leaflet-control-layers, .toggle-panel-button, .leaflet-right-panel'); + const controls = document.querySelectorAll('.leaflet-control-layers, .toggle-panel-button, .leaflet-right-panel .drawer-button'); controls.forEach(control => { control.classList.toggle('controls-shifted'); }); @@ -1402,7 +1408,7 @@ export default class extends BaseController { drawer.style.maxHeight = '100vh'; drawer.innerHTML = ` -
Loading visits...
@@ -1426,6 +1432,7 @@ export default class extends BaseController { const startAt = urlParams.get('start_at') || new Date().toISOString(); const endAt = urlParams.get('end_at') || new Date().toISOString(); + console.log('Fetching visits for:', startAt, endAt); const response = await fetch( `/api/v1/visits?start_at=${encodeURIComponent(startAt)}&end_at=${encodeURIComponent(endAt)}`, { @@ -1461,22 +1468,215 @@ export default class extends BaseController { return; } - // Clear existing circles + // Clear existing visit circles this.visitCircles.clearLayers(); - // Draw circles only for confirmed visits + // Draw circles for all visits visits - .filter(visit => visit.status === 'confirmed') + .filter(visit => visit.status !== 'declined') .forEach(visit => { if (visit.place?.latitude && visit.place?.longitude) { + const isSuggested = visit.status === 'suggested'; const circle = L.circle([visit.place.latitude, visit.place.longitude], { - color: '#4A90E2', - fillColor: '#4A90E2', - fillOpacity: 0.2, + color: isSuggested ? '#FFA500' : '#4A90E2', // Border color + fillColor: isSuggested ? '#FFD700' : '#4A90E2', // Fill color + fillOpacity: isSuggested ? 0.4 : 0.6, radius: 100, - weight: 2 + weight: 2, + interactive: true, + bubblingMouseEvents: false, + pane: 'visitsPane', + dashArray: isSuggested ? '4' : null // Dotted border for suggested }); + + // Add the circle to the map this.visitCircles.addLayer(circle); + + // Fetch possible places for the visit + const fetchPossiblePlaces = async () => { + try { + // Close any existing popup before opening a new one + if (this.currentPopup) { + this.map.closePopup(this.currentPopup); + this.currentPopup = null; + } + + const response = await fetch(`/api/v1/visits/${visit.id}/possible_places`, { + headers: { + 'Accept': 'application/json', + 'Authorization': `Bearer ${this.apiKey}`, + } + }); + + if (!response.ok) throw new Error('Failed to fetch possible places'); + + const possiblePlaces = await response.json(); + + // Create popup content with form and dropdown + const defaultName = visit.name; + const popupContent = ` +