some big development in mapping

c32f492 · gmorell · 2025-09-15 16:07

11 files +132 -3

Files changed

modified apps/room_sanctum/assets/js/hooks/leaflet_map.js
+67 −3
@@ -405,6 +405,21 @@ const LeafletMap = {
405 405 const popupContent = this.createFreeBikePopupContent(bike);
406 406 marker.bindPopup(popupContent);
407 407
408 + // Add event listener for the add query button after popup opens
409 + marker.on('popupopen', (e) => {
410 + const popup = e.popup;
411 + const addQueryBtn = popup.getElement().querySelector('.add-area-query-btn');
412 + if (addQueryBtn) {
413 + addQueryBtn.addEventListener('click', () => {
414 + this.pushEvent('add-query-from-map', {
415 + station_id: bike.bike_id,
416 + name: 'Free Bike Area Query',
417 + type: 'area'
418 + });
419 + });
420 + }
421 + });
422 +
408 423 return marker;
409 424 },
410 425
@@ -419,6 +434,21 @@ const LeafletMap = {
419 434 const popupContent = this.createStationPopupContent(station);
420 435 marker.bindPopup(popupContent);
421 436
437 + // Add event listener for the add query button after popup opens
438 + marker.on('popupopen', (e) => {
439 + const popup = e.popup;
440 + const addQueryBtn = popup.getElement().querySelector('.add-query-btn');
441 + if (addQueryBtn) {
442 + addQueryBtn.addEventListener('click', () => {
443 + this.pushEvent('add-query-from-map', {
444 + station_id: station.station_id,
445 + name: station.name || 'Station',
446 + type: 'station'
447 + });
448 + });
449 + }
450 + });
451 +
422 452 return marker;
423 453 },
424 454
@@ -659,10 +689,22 @@ const LeafletMap = {
659 689 </div>
660 690 ` : ''}
661 691
662 − <div class="text-xs text-gray-500">
692 + <div class="text-xs text-gray-500 mb-2">
663 693 <i class="fa-solid fa-location-dot mr-1"></i>
664 694 ${bike.lat.toFixed(4)}, ${bike.lng.toFixed(4)}
665 695 </div>
696 +
697 + <div class="flex justify-center mt-2">
698 + <button
699 + class="add-area-query-btn btn btn-sm btn-secondary text-xs px-3 py-1 rounded-md bg-green-600 hover:bg-green-700 text-white transition-colors"
700 + data-bike-id="${bike.bike_id}"
701 + data-query-type="area"
702 + title="Create an area query around this bike location"
703 + >
704 + <i class="fa-solid fa-plus mr-1"></i>
705 + Add Area Query
706 + </button>
707 + </div>
666 708 </div>
667 709 `;
668 710 },
@@ -751,10 +793,22 @@ const LeafletMap = {
751 793 </div>
752 794 ` : ''}
753 795
754 − <div class="text-xs text-gray-500">
796 + <div class="text-xs text-gray-500 mb-2">
755 797 <i class="fa-solid fa-location-dot mr-1"></i>
756 798 ${station.lat.toFixed(4)}, ${station.lng.toFixed(4)}
757 799 </div>
800 +
801 + <div class="flex justify-center mt-2">
802 + <button
803 + class="add-query-btn btn btn-sm btn-primary text-xs px-3 py-1 rounded-md bg-blue-600 hover:bg-blue-700 text-white transition-colors"
804 + data-station-id="${station.station_id}"
805 + data-station-name="${(station.name || 'Station').replace(/"/g, '&quot;')}"
806 + data-query-type="station"
807 + >
808 + <i class="fa-solid fa-plus mr-1"></i>
809 + Add Query
810 + </button>
811 + </div>
758 812 </div>
759 813 `;
760 814 },
@@ -789,10 +843,20 @@ const LeafletMap = {
789 843 </div>
790 844 ` : ''}
791 845
792 − <div class="text-xs text-gray-500">
846 + <div class="text-xs text-gray-500 mb-2">
793 847 <i class="fa-solid fa-location-dot mr-1"></i>
794 848 ${query.lat.toFixed(4)}, ${query.lng.toFixed(4)}
795 849 </div>
850 +
851 + <div class="flex justify-center mt-2">
852 + <button
853 + class="btn btn-sm btn-primary text-xs px-3 py-1 rounded-md bg-blue-600 hover:bg-blue-700 text-white transition-colors"
854 + onclick="window.liveSocket.execJS(this, [['push', {event: 'add-query-from-map', value: {station_id: '${query.id}', name: '${query.name.replace(/'/g, "\\'")}', type: 'query'}}]])"
855 + >
856 + <i class="fa-solid fa-plus mr-1"></i>
857 + Duplicate Query
858 + </button>
859 + </div>
796 860 </div>
797 861 `;
798 862 },
modified apps/room_sanctum/lib/room_sanctum_web/live/cfg_source_live/show.ex
+65 −0
@@ -235,6 +235,71 @@ defmodule RoomSanctumWeb.SourceLive.Show do
235 235 {:noreply, socket |> assign(:tester_selected, nil) |> assign(:tester_selected_name, nil)}
236 236 end
237 237
238 + @impl true
239 + def handle_event("add-query-from-map", %{"station_id" => station_id, "name" => name, "type" => type}, socket) do
240 + case {socket.assigns.source.type, type} do
241 + {:gbfs, "station"} ->
242 + Configuration.create_query(
243 + %{
244 + user_id: socket.assigns.current_user.id,
245 + source_id: socket.assigns.source.id,
246 + name: "#{name} - Station Query",
247 + query: %{"stop_id" => station_id, "__type__" => "gbfs"},
248 + public: true
249 + }) |> IO.inspect
250 +
251 + {:gbfs, "area"} ->
252 + # For free bike area queries, create a radius-based query around the bike location
253 + # We'll use a default 500m radius, but this could be made configurable
254 + bike = Enum.find(socket.assigns.free_bikes, &(&1.bike_id == station_id))
255 + if bike do
256 + Configuration.create_query(
257 + %{
258 + user_id: socket.assigns.current_user.id,
259 + source_id: socket.assigns.source.id,
260 + name: "Free Bikes around #{bike.lat}, #{bike.lon}",
261 + query: %{
262 + "lat" => bike.lat,
263 + "lng" => bike.lon,
264 + "radius" => 500, # 500 meter radius
265 + "__type__" => "gbfs"
266 + },
267 + public: true
268 + }) |> IO.inspect
269 + end
270 +
271 + {:gtfs, "stop"} ->
272 + Configuration.create_query(
273 + %{
274 + user_id: socket.assigns.current_user.id,
275 + source_id: socket.assigns.source.id,
276 + name: "#{name} - Stop Query",
277 + query: %{"stop" => station_id, "__type__" => "gtfs"},
278 + public: true
279 + }) |> IO.inspect
280 +
281 + {_, "query"} ->
282 + # For duplicating existing queries, find the original and copy it
283 + original_query = Enum.find(socket.assigns.queries, &(&1.id == String.to_integer(station_id)))
284 + if original_query do
285 + Configuration.create_query(
286 + %{
287 + user_id: socket.assigns.current_user.id,
288 + source_id: socket.assigns.source.id,
289 + name: "Copy of #{original_query.name}",
290 + query: original_query.query,
291 + public: true
292 + }) |> IO.inspect
293 + end
294 +
295 + _ ->
296 + IO.inspect("Unhandled query creation for type: #{type}, source: #{socket.assigns.source.type}")
297 + end
298 +
299 + # Show a temporary success message or update
300 + {:noreply, socket |> put_flash(:info, "Query created successfully!")}
301 + end
302 +
238 303 @impl true
239 304 def handle_event("select-foci", %{"foci" => foci, "distance" => distance} = data, socket) do
240 305 IO.inspect(data)

Parents: 18ad607